工作小数点数
Posted
技术标签:
【中文标题】工作小数点数【英文标题】:working decimal point numbers 【发布时间】:2013-12-10 12:08:03 【问题描述】:我用java写了一个关于浮点的程序,但是得到的输出不准确;而用 C 编写的相同程序确实产生了准确的结果。
代码片段:
public class One
public static void main(String...args)
double i, num=0.0;
for(i=0;i<10;i++)
num=num+0.1;
System.out.println(num);
输出:0.9999999999999999
C语言的程序是这样的
#include<stdio.h>
main()
double i,num=0.0;
for(i=0;i<10;i++)
num=num+0.1;
printf("%f",num);
输出:1.00000
我做错了什么?
【问题讨论】:
为什么你没有被 c 标记? How to make strings from floating-point numbers with '.' (dot) as a decimal separator and not more than 3 digits after floating point?的可能重复 您是否尝试过在 Java 中使用等效的printf
?你在比较苹果和橘子。
【参考方案1】:
C 隐藏了问题而不是删除它
C 程序更准确的想法是对正在发生的事情的误解。两者都有不精确的答案,但默认情况下 C 已四舍五入为 6 个有效数字。 隐藏微小的错误。如果您在计算中实际使用该值(例如num==1
),您会发现两者都不准确。
通常,写得好的程序并不重要
一般来说,智能编写的程序可以毫无困难地处理这个微小的错误。例如,您的程序可以重写为每次重新创建一个双精度数
double i, num=0.0;
for(i=0;i<10;i++)
num=0.1*i;
System.out.println(num);
意味着错误不会增长。此外,您永远不应该将 == 与双打一起使用,因为在那里可以看到微小的不准确。
在非常非常偶然的情况下,这个微小的错误是一个问题(货币程序是最常见的);可以使用 bigDecimal。
这不是浮点数的问题,而是从基数 10 到基数 2 的转换。
以 10 为底的分数无法精确表达;例如 1/3。类似地,有些分数不能用二进制精确表示,例如 1/10。 It is from this perspective that you should look at this
在这种情况下的问题是,当你写“0.1”时,一个以 10 为基数的数字,计算机必须永远将其转换为二进制数,0.1=(binary)0.00011001100110011001100110011001.......
,但因为它不能用空格精确地表示二进制数它最终成为(binary)0.000110011001100
1。二进制友好数字(例如 1/2)将完全准确,直到双精度数字用完(此时即使二进制友好数字也无法精确表示)
1小数位数不准确
【讨论】:
【参考方案2】:尝试使用BigDecimal
。浮点数表示是 Java 的一个古老的争论点(不仅如此)。
double i;
BigDecimal num = BigDecimal.ZERO;
for(i=0;i<10;i++)
num = num.add(new BigDecimal("0.1"));
System.out.println(num);
【讨论】:
这是一个奇怪的情况,java 是诚实的,而 c 试图隐藏它,因此 java 被认为不太准确,sigh【参考方案3】:问题不在于 Java,而在于计算机如何用二进制表示浮点数。有些数字无法准确表示,因此在添加0.1
时会出现一点舍入误差。我建议您阅读this great article 以获得详细说明。此外,还有algorithms 专门设计用于在添加数字序列时最大限度地减少错误。
【讨论】:
【参考方案4】:这是floating
数字表示中的一个问题。使用BigDecimal
您可以在这里理解问题。如果你运行以下代码,
double i, num=0.0;
for(i=0;i<10;i++)
System.out.println(num);
num=num+0.1;
System.out.println(num);
输出
0.0
0.1
0.2
0.30000000000000004 // wrong value, it should be 0.3
0.4
0.5
0.6
0.7
0.7999999999999999 // this one should be 0.7+0.1=0.8
0.8999999999999999 // this should be 0.8+0.1=0.9
0.9999999999999999 // final result should be 0.9+0.1=1
让我们试试BigDeciaml
double i;
BigDecimal num=BigDecimal.ZERO;
for(i=0;i<10;i++)
System.out.println(num);
num=num.add(new BigDecimal("0.1"));
System.out.println(num);
输出
0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1.0
【讨论】:
【参考方案5】:有一个strictfp
关键字,比如:
strictfp class Example
//your code here
strictfp
是在 Java SE 2(或附近)中引入的关键字,因为浮点模型放宽了一点。
【讨论】:
您能解释一下strictfp
的含义/作用
通过我的阅读,strictfp 确保所有系统上的等效浮点行为,而不是使用 base-10 数字系统而不是 base-2
@RichardTingle Base-10 与浮点无关。 strictfp
只是通过任何必要的手段来确保 IEEE754 合规性,例如使用软件而不是 FP 指令。
@EPJ 这是我的观点,strictfp 不会影响这个问题;在以 2 为底的系统中表示以 10 为底的数字(浮点最终会导致问题,但它是以 10 为底的 --> 以 2 为底的数字,这是大部分问题所在)以上是关于工作小数点数的主要内容,如果未能解决你的问题,请参考以下文章
如果是浮点数则显示小数点 2 位,如果是整数则显示小数点数 0 位 [重复]