Java 中 float 和 double 基元的比较

发布于 2024-12-03 23:27:50 字数 520 浏览 1 评论 0原文

我遇到了 Java 的一个奇怪的角落。(这对我来说很奇怪)

double dd = 3.5;          
float ff = 3.5f;
System.out.println(dd==ff);   

o/p: true

double dd = 3.2;
float ff = 3.2f;
System.out.println(dd==ff);

o/p: false

我观察到,如果我们比较任何两个值 (正如我在示例中提到的浮点数和双精度数),其中 .5.0 如 3.5、234.5、645.0 那么输出为true,即两个值相等,否则输出为false,尽管它们相等。

即使我尝试创建方法 strictfp 但没有成功。 我是不是错过了什么。

I came across a strange corner of Java.(It seems strange to me)

double dd = 3.5;          
float ff = 3.5f;
System.out.println(dd==ff);   

o/p: true

double dd = 3.2;
float ff = 3.2f;
System.out.println(dd==ff);

o/p: false

I observed that if we compare any two values (a float and a double as I mentioned in the example) with .5 OR .0 like 3.5, 234.5, 645.0
then output is true i.e. two values are equal otherwise output is false though they are equals.

Even I tried to make method strictfp but no luck.
Am I missing out on something.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

天赋异禀 2024-12-10 23:27:50

查看每个计算机科学家都应该了解的浮点知识数字

<块引用>

将无限多个实数压缩为有限数量的位数需要近似表示......

--- 编辑以显示上面引用的含义 ---

您不应该比较浮点数或双精度数是否相等;因为,您无法真正保证分配给浮点型或双精度型的数字是准确的。

因此

 float x = 3.2f;

不会产生值为 3.2 的浮点数。它会产生值为 3.2 加上或减去一些非常小的误差的浮点数。说 3.19999999997f。现在应该很明显为什么比较不起作用了。

要明智地比较浮点数是否相等,您需要检查该值是否“足够接近”相同的值,如下所示

float error = 0.000001 * second;
if ((first >= second - error) || (first <= second + error)) {
   // close enough that we'll consider the two equal
   ...
}

Take a look at What every computer scientist should know about floating point numbers.

Squeezing infinitely many real numbers into a finite number of bits requires an approximate representation....

--- Edit to show what the above quote means ---

You shouldn't ever compare floats or doubles for equality; because, you can't really guarantee that the number you assign to the float or double is exact.

So

 float x = 3.2f;

doesn't result in a float with a value of 3.2. It results in a float with a value of 3.2 plus or minus some very small error. Say 3.19999999997f. Now it should be obvious why the comparison won't work.

To compare floats for equality sanely, you need to check if the value is "close enough" to the same value, like so

float error = 0.000001 * second;
if ((first >= second - error) || (first <= second + error)) {
   // close enough that we'll consider the two equal
   ...
}
凝望流年 2024-12-10 23:27:50

区别在于 3.5 可以用 floatdouble精确表示 - 而 3.2 则不能用这两种类型精确表示...并且两个最接近的近似值是不同的。

想象一下,我们有两种固定精度的十进制类型,其中一种存储 4 位有效数字,另一种存储 8 位有效数字,我们要求它们中的每一个存储最接近“三分之一”的数字(但我们可能会这样做)。那么,一个的值为 0.3333,一个的值为 0.33333333。

floatdouble 之间的相等比较首先将 float 转换为 double,然后比较两者 - 这将相当于将“小十进制”类型中的 0.3333 转换为 0.33330000。然后它会比较 0.33330000 和 0.33333333 是否相等,并给出 false 结果。

The difference is that 3.5 can be represented exactly in both float and double - whereas 3.2 can't be represented exactly in either type... and the two closest approximations are different.

Imagine we had two fixed-precision decimal types, one of which stored 4 significant digits and one of which stored 8 significant digits, and we asked each of them to store the number closest to "a third" (however we might do that). Then one would have the value 0.3333 and one would have the value 0.33333333.

An equality comparison between float and double first converts the float to a double and then compares the two - which would be equivalent to converting 0.3333 in our "small decimal" type to 0.33330000. It would then compare 0.33330000 and 0.33333333 for equality, and give a result of false.

仅冇旳回忆 2024-12-10 23:27:50

浮点是一种二进制格式,它可以将数字表示为 2 的幂之和。例如,3.5 是 2 + 1 + 1/2。

float 3.2f 作为 3.2 的近似值

2 + 1 + 1/8+ 1/16+ 1/128+ 1/256+ 1/2048+ 1/4096+ 1/32768+ 1/65536+ 1/524288+ 1/1048576+ 1/4194304 + a small error

但是 double 3.2d 作为 3.2 的近似值

2 + 1 + 1/8+ 1/16+ 1/128+ 1/256+ 1/2048+ 1/4096+ 1/32768+ 1/65536+ 1/524288+ 1/1048576+ 1/8388608+ 1/16777216+ 1/134217728+ 1/268435456+ 1/2147483648+ 1/4294967296+ 1/34359738368+ 1/68719476736+ 1/549755813888+ 1/1099511627776+ 1/8796093022208+ 1/17592186044416+ 1/140737488355328+ 1/281474976710656+ 1/1125899906842624 + a smaller error

当您使用浮点时,您需要使用适当的舍入。如果您使用 BigDecimal(很多人都这样做),它会内置舍入。

double dd = 3.2;          
float ff = 3.2f;
// compare the difference with the accuracy of float.
System.out.println(Math.abs(dd - ff) < 1e-7 * Math.abs(ff));

顺便说一句,我用来打印 double 分数的代码。

double f = 3.2d;
double f2 = f - 3;
System.out.print("2+ 1");
for (long i = 2; i < 1L << 54; i <<= 1) {
  f2 *= 2;
  if (f2 >= 1) {
    System.out.print("+ 1/" + i);
    f2 -= 1;
  }
}
System.out.println();

floating point is a binary format and it can represent numbers as a sum of powers of 2. e.g. 3.5 is 2 + 1 + 1/2.

float 3.2f as an approximation of 3.2 is

2 + 1 + 1/8+ 1/16+ 1/128+ 1/256+ 1/2048+ 1/4096+ 1/32768+ 1/65536+ 1/524288+ 1/1048576+ 1/4194304 + a small error

However double 3.2d as an approximation of 3.2 is

2 + 1 + 1/8+ 1/16+ 1/128+ 1/256+ 1/2048+ 1/4096+ 1/32768+ 1/65536+ 1/524288+ 1/1048576+ 1/8388608+ 1/16777216+ 1/134217728+ 1/268435456+ 1/2147483648+ 1/4294967296+ 1/34359738368+ 1/68719476736+ 1/549755813888+ 1/1099511627776+ 1/8796093022208+ 1/17592186044416+ 1/140737488355328+ 1/281474976710656+ 1/1125899906842624 + a smaller error

When you use floating point, you need to use appropriate rounding. If you use BigDecimal instead (and many people do) it has rounding built in.

double dd = 3.2;          
float ff = 3.2f;
// compare the difference with the accuracy of float.
System.out.println(Math.abs(dd - ff) < 1e-7 * Math.abs(ff));

BTW the code I used to print the fractions for double.

double f = 3.2d;
double f2 = f - 3;
System.out.print("2+ 1");
for (long i = 2; i < 1L << 54; i <<= 1) {
  f2 *= 2;
  if (f2 >= 1) {
    System.out.print("+ 1/" + i);
    f2 -= 1;
  }
}
System.out.println();
金兰素衣 2024-12-10 23:27:50

浮点数的常见实现,IEEE754,只允许精确表示那些具有短的、有限的二进制展开式的数字,即,它们是有限多个(邻近的)2 的幂的和。所有其他数字都无法精确表示。

由于 floatdouble 具有不同的大小,因此两种类型中不可表示值的表示方式不同,因此它们比较不相等。

(二进制字符串的长度就是尾数的大小,因此对于float来说是24,对于double来说是53,对于80-位扩展精度浮点数(Java 中没有)。小数位由指数确定。)

The common implementation of floating point numbers, IEEE754, allows for the precise representation of only those numbers which have a short, finite binary expansion, i.e. which are a sum of finitely many (nearby) powers of two. All other numbers cannot be precisely represented.

Since float and double have different sizes, the representation in both types for a non-representable value are different, and thus they compare as unequal.

(The length of the binary string is the size of the mantissa, so that's 24 for float, 53 for double and 64 for the 80-bit extended-precision float (not in Java). The scale is determined by the exponent.)

若水微香 2024-12-10 23:27:50

这应该有效:

BigDecimal ddBD = new BigDecimal(""+dd);
BigDecimal ffBD = new BigDecimal(""+ff);

// test for equality
ddBO.equals(ffBD);

当您想要比较浮点数或双精度数时,始终使用 BigDecimal
并始终使用带有字符串参数的 BigDecimal 构造函数!

This should work:

BigDecimal ddBD = new BigDecimal(""+dd);
BigDecimal ffBD = new BigDecimal(""+ff);

// test for equality
ddBO.equals(ffBD);

Always work with BigDecimal when you want to compare floats or doubles
and always use the BigDecimal constructor with the String parameter!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文