考虑浮点数0.644696875。让我们用Java和C把它转换成八位小数的字符串:
import java.lang.Math;
public class RoundExample{
public static void main(String[] args){
System.out.println(String.format("%10.8f",0.644696875));
}
}
结果:0.64469688
自己试试吧:http://tpcg.io/oszC0w
#include <stdio.h>
int main()
{
printf("%10.8f", 0.644696875); //double to string
return 0;
}
结果:0.64469687
自己试试吧:http://tpcg.io/fQqSRF
为什么最后一个数字不同?
数字0.644696875不能精确地表示为机器号。它表示为分数2903456606016923/4503599627370496,其值为0.64668799999
诚然,这是一个边缘案例。但我真的很好奇差异的来源。
相关: https://mathematica.stackexchange.com/questions/204359/is-numberform-double-rounding-numbers
这里可能发生的情况是,他们使用稍微不同的方法将数字转换为字符串,这引入了舍入误差。在编译过程中,字符串转换为浮点的方法也可能不同,由于舍入,它们的值也可能略有不同。
但是请记住,float的小数精度为24位,也就是大约7.22个十进制数字[log10(2)*24],前7个数字是一致的,因此只有最后几个最低有效位不同。
欢迎来到浮点数学的有趣世界,2 2并不总是等于4。
在这种情况下,Java 规范需要麻烦的双舍五入。数字 0.6446968749999999470645661858725361526012420654296875 首先转换为 0.644696875,然后舍入为 0.64469688。
相比之下,C实现简单地将0.64469687499947064566185872536156012420654296875直接四舍五入到8位,产生0.6446 9687。
对于双精度
型,Java 使用 IEEE-754 基本 64 位二进制浮点数。在此格式中,最接近源文本中数字的值 0.644696875 是 0.64469696874999999470645661858725361526012420654296875,我相信这是使用 String.format(“.8f”,0.644696875)
格式化的实际值。1
使用< code>Double类型和< code>f格式进行格式化的文档说明如下:
…如果精度小于分别由< code > float . tostring(float)或< code > double . tostring(double)返回的字符串中小数点后出现的位数,则将使用round half up算法对值进行舍入。否则,可能会附加零以达到精度…
让我们考虑“由…< code > double . tostring(double)返回的字符串”。对于数字0.6446968749999999470645661858725361526012420654296875,此字符串为“0.644696875”。这是因为Java规范规定< code>toString产生的十进制数字刚好足以唯一区分< code>Double值集合中的数字,在这种情况下,“0.644696875”刚好有足够的数字。第2页
该数字在小数点后有九位数字,“.8f”
请求八位,因此上面引用的段落说“值”是四舍五入的。它指的是哪个值 - 格式
的实际操作数,即 0.64469696874999999470645661858725361526012420654296875,还是它提到的字符串“0.644696875”?由于后者不是数值,我本来以为“值”是指前者。但是,第二句话说“否则[即,如果请求更多数字],可能会附加零......”如果我们使用格式
的实际操作数,我们将显示其数字,而不是使用零。但是,如果我们将字符串作为数值,则其十进制表示形式在中显示的数字后面将只有零。因此,这似乎是预期的解释,而Java实现似乎符合这一点。
因此,要使用".8f"
格式化这个数字,我们首先将其转换为0.644696875,然后使用舍入半向上规则对其进行舍入,从而产生0.64469688。
这是一个糟糕的规范,因为:
(另外,很遗憾他们写了零“可能”附加。为什么不“否则,附加零以达到精度”?对于“may”,似乎他们给了实现一个选择,尽管我怀疑他们的意思是“可能”是基于是否需要零来达到精度,而不是基于实现者是否选择附加它们。
1当源代码中的0.644696875
转换为Double
时,我相信结果应该是Double
格式中可表示的最接近值。(我没有在Java留档中找到它,但它符合要求实现行为相同的Java哲学,我怀疑转换是根据Double.valueOf(String s)
完成的,它确实需要这个。)最接近0.644696875的Double
是0.64469687499999470645661858725361526012420654296875。
2如果数字较少,七位数0.64469687是不够的,因为最接近它的Double
值为0.6446968699999999774519210404832847416400909423828125。所以需要八位数字来唯一区分0.64469687499999470645661858725361526012420654296875。
问题内容: Ada,Pascal和许多其他语言都支持范围,这是对整数进行子类型的一种方式。范围是一个有符号整数值,范围从一个值(第一个)到另一个值(最后一个)。实现一个在OOP中执行相同操作的类很容易,但是我认为本机支持该功能可以使编译器进行其他静态检查。 我知道无法静态地验证范围内定义的变量不会“溢出”运行时(即由于输入错误),但是我认为可以做些什么。我考虑了按合同设计方法(Eiffel)和Sp
问题内容: 多年前,当我开始面向对象编程时,给人的印象是变量(如果是正确的词)是“原始”(int,double等)或一流对象(String,JPane等)。最近关于Java和C#中的基元的答案对此予以加强(@DanielPryden:Java和C#中的基元类型是否不同?。但是,不知道C#ValueTypes是基元,对象还是其他野兽(例如第二类对象)。我看到SO只能使用标签的一种,因此也许它不再是一
为什么mysql中IS TRUE和=True的结果不一样? 我有一张user表,结构如下: 表中数据如下: 我尝试查询sql: 结果为: 查询sql: 结果为: 我用true或者false作为查询条件是因为:在java中tinyint能被转成Boolean,所以在查询的时候能直接传true或者false 有没有大佬知道为什么结果不一样呢?
问题内容: 我们注意到,用C#(或Java)开发的软件中的许多错误都导致NullReferenceException。 为什么在语言中甚至包含了“ null”? 毕竟,如果没有“ null”,那么我就不会有错误,对吧? 换句话说,如果没有null,该语言的什么功能将无法正常工作? 问题答案: “ C#父亲” Anders Hejlsberg在他的《计算机世界》采访中谈到了这一点: 例如,在类型系统
我编写了一个名为“dateutils”的静态类,这里是一个名为“parsedate(String)”的静态方法,它将使用一些模式将字符串转换为日期。默认时区为亚洲/上海(我在中国) 并将其传递给方法timeZone.setDefault(timeZone);并使用SimpleDateFormat来协调字符串。匹配的模式应该是“EEE,dd MMM yyyy HH:MM:SS ZZZ”,这里有三个测
问题内容: 我知道前缀和posfix操作… i和i 之间的区别等等。 但是我想我在这里想不到的东西。在下面可以找到代码: 因此输出为: 我在C中尝试了相同的代码: 输出为: 为什么在C中相同的代码增加值时却不增加? 问题答案: 爪哇 在Java中,表达式具有明确定义的含义。复合赋值运算符的规范说: 形式为 E1 op = E2 的复合赋值表达式等效于 E1 =(T)((E1)op(E2)) ,其中