以最小的精度损失将 float 转换为 short [关闭]

Posted

技术标签:

【中文标题】以最小的精度损失将 float 转换为 short [关闭]【英文标题】:convert float to short with minimal loss of precision [closed] 【发布时间】:2014-08-08 10:23:08 【问题描述】:

我有这个生成浮点值(例如 0.37885)的正弦波,但我希望它们作为短裤。用 short 直接转换给我的值为 0。那么解决方案是什么?

谁能告诉我怎么做 - 理想情况下不损失精度 - 或者如果这是可能的,那么精度损失最小?

【问题讨论】:

float 的大小通常为 4 个字节,short 的大小通常为 2 个字节。在将 4 个字节的数据压缩成 2 个字节的数据时,您究竟希望如何避免精度损失? 为了帮助理解你试图解决的问题,你能解释一下为什么你需要在 short 中存储一个浮点数吗? 另外,你打算如何将浮点值“转换”为非浮点值? 您需要决定将某个点用于最低位,或者像 FPU 通常那样编写一些代码来存储float @BackSlash:这不是问题。如果您采用相同大小的整数(int 在大多数平台上都可以),那么数据类型就没有问题。例如,给定float fint i,您可以使用i = *(int*)&f 【参考方案1】:
public static short floatToShort(float x) 
    if (x < Short.MIN_VALUE) 
        return Short.MIN_VALUE;
    
    if (x > Short.MAX_VALUE) 
        return Short.MAX_VALUE;
    
    return (short) Math.round(x);

你会丢失小数部分:

float    4 byte floating-point
double   8 byte floating-point (normal)
short    2 byte integer
int      4 byte integer (normal)
long     8 byte integer

编辑:

也许您想知道如何将 float(4 个字节)的位保存到 int(4 个字节)中: (http://docs.oracle.com/javase/7/docs/api/java/lang/Float.html#floatToRawIntBits(float))

float x = 0.1f;
int n = Float.floatToRawIntBits(x);
float y = Float.intBitsToFloat(n);

【讨论】:

我同意会有精度损失,但我想要的只是一种解决方法。我会将其标记为答案(如果允许的话)。 感谢保存位方法。这会很有帮助。【参考方案2】:

原则上,您可以将其乘以 100000,将其转换为 int,然后减去 -32,767 并将其转换为 short。如果您的所有值仍然在 -32,767 到 32,767 范围内,那可能是您能做的最好的事情。否则,您将不得不限制您的精度并乘以 10000。

当然,当你使用 short 时,你必须记住将其分割回去。

【讨论】:

我认为这是 only 正确答案,但假设他的正弦波返回值介于 -1 和 1(含)之间,我会将它们乘以 65535,然后减去 32767 . 这行不通。例如 1 的值:1 * 65535 - 32767 = 32768。这是错误的,它超出了短范围。其他示例:-1 * 65535 - 32767 将给出 -98302。【参考方案3】:

如果您输入的 float 值在定义的范围内(现在假设它们在 -1..1 的范围内,不包括在内),您可以将它们相乘以获得您将丢弃的分数的值。

有效的短范围是:-32768..32767,因此您可以在这种情况下与32768 进行倍数(最大短/最大输入值)。

例如:

float f = 0.23451f;
short s = (short) (f * 32768);

要将short 值解码为float

float f2 = s / 32768f;

【讨论】:

【参考方案4】:

short 是一个integral type,所以它只能包含整数。在short0.37885 的唯一两个选择是01,这两者(在我看来)都失去了相当多的精度。

所以答案是:如果您可以丢失所有小数值,请使用强制转换 Float#shortValueMath.round(float)(并将生成的 int 强制转换为 short)。

示例:Live Copy

float f1 = 0.37885f;
short s1 = (short)Math.round(f1);
System.out.println("s1 = " + s1);

float f2 = 27.67885f;
short s2 = (short)Math.round(f2);
System.out.println("s2 = " + s2);

输出:

s1 = 0 s2 = 28

在你说的评论中:

我有这个正弦波,它会生成上面提到的值,但我希望它们作为短裤。

啊,现在,我们可以用它做点什么了。大概你得到的值都在01 之间。您可以通过乘法将它们存储为短裤。由于short 的范围是 -32,768 到 37,767,因此乘以它们的方便数字可能是 10000:

short s = Math.round(floatValue * 10000);

我们为您的示例获得的号码是3789。示例:Live Copy

float floatValue = 0.37885f;
short s = (short)Math.round((double)floatValue * 10000);
System.out.println("s = " + s);

这不是相同的值,当然,它是乘以一万的值,所以你要在任何地方使用它,你必须允许它。 p>

【讨论】:

为什么这是个问题?如果您采用相同大小的整数(int 在大多数平台上都可以),那么数据类型就没有问题。例如,给定float fint i,您可以使用i = *(int*)&amp;f @barakmanos 那是什么&amp; @barakmanos:这是 Java,而不是 C。您可能也可以在 Java 中做类似的事情,但是 A) floatshort 不是大小相同,并且 B)OP 不太可能想要组成float 的位的short(或int)视图。 :-) 哎呀,对不起(@BackSlash - 向你道歉)...... :) @barakmanos 很有趣,你知道它只是存储位,但数学值完全不同。 Java有Float.floatToRawIntBits

以上是关于以最小的精度损失将 float 转换为 short [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

第二周学习

java相关面试的基础知识

java中类型转化及例题

动手动脑

有关强制类型转换和自动类型转换

Java中不同类型数据是不是可以运算?例如:单精度和int类型是不是可以直接相加?