流行测验:以小数表示1/3。
答案:您不能;不能。不完全是
计算机以二进制计数。还有更多数字“无法完全代表”。就像在十进制问题中一样,如果您只需要写一小块纸,则可以简单地使用0.3333333
并将其命名为一天,然后得到一个非常接近的数字与1 / 3
相同,但并不完全相同,因此计算机也代表分数。
或者,这样考虑:浮点数占用32位;双占64位。32位值只能表示2 ^ 32(约40亿)个不同的数字。但是,即使在0到1之间,也有无限数量的数字。因此,鉴于最多有2 ^ 32个具体的具体数字可以“精确地”表示为浮点数,因此,在约40亿个值的受祝福集合中没有的任何数字都无法表示。您可以从这个40亿个可表示的值池中简单地得到一个值,而不是仅仅出错,它是最接近您想要的值。
此外,由于计算机以二进制而不是十进制计数,所以您对“可表示”和“不可以表示”的感觉已经关闭。您可能会认为1/3是个大问题,但肯定1/10很容易,对吧?就是0.1
,这是一个精确的表示。啊,但是十分之一在十进制中效果很好。毕竟,十进制是基于数字10的,这并不奇怪。但是用二进制?一半,四分之一,八分之一,十六分之一:二进制容易。十分之一?这是第三个困难:不可复制。
0.9本身不是可表示的数字。但是,当您打印浮标时,就是这样。
原因是,打印浮动/双精度是一门艺术,而不是一门科学。假设只有少数数字是可表示的,并且由于二进制v。十进制的原因,这些数字对人类而言并不“自然”,那么您确实需要在数字上添加“取整”策略,否则看起来疯狂(没人想读0.899999999999999999765)。而这正是System.out.println和合作伙伴所做的。
但是您确实应该控制舍入功能:切勿使用System.out.println打印双精度和浮点型。请改用System.out.printf("%.6f",yourDouble);
,在这种情况下,两者都将打印0.9
。因为虽然两者都不能真正精确地表示0.9,但最接近浮点数的数字(或者更确切地说,就是取最接近2.0的数字(即2.0)和最接近1.1的数字(不是精确地1.1)),减去它们,然后找到最接近该结果的数字)–即使不是浮点数也打印为0.9,并且不打印为0.9的两倍。
,
float
和double
之间的区别:
让我们在一个简单的C程序中运行数字,以便获得其二进制表示形式:
#include <stdio.h>
typedef union {
float val;
struct {
unsigned int fraction : 23;
unsigned int exponent : 8;
unsigned int sign : 1;
} bits;
} F;
typedef union {
double val;
struct {
unsigned long long fraction : 52;
unsigned long long exponent : 11;
unsigned long long sign : 1;
} bits;
} D;
int main() {
F f = {(float )(2.0 - 1.1)};
D d = {(double)(2.0 - 1.1)};
printf("%d %d %d\n",f.bits.sign,f.bits.exponent,f.bits.fraction);
printf("%lld %lld %lld\n",d.bits.sign,d.bits.exponent,d.bits.fraction);
return 0;
}
此代码的打印输出为:
0 126 6710886
0 1022 3602879701896396
基于上述两种格式规范,让我们将这些数字转换为有理值。
为了获得高精度,让我们在一个简单的Python程序中做到这一点:
from decimal import Decimal
from decimal import getcontext
getcontext().prec = 100
TWO = Decimal(2)
def convert(sign,exponent,fraction,e_len,f_len):
return (-1) ** sign * TWO ** (exponent - 2 ** (e_len - 1) + 1) * (1 + fraction / TWO ** f_len)
def toFloat(sign,fraction):
return convert(sign,8,23)
def toDouble(sign,11,52)
f = toFloat(0,126,6710886)
d = toDouble(0,1022,3602879701896396)
print('{:.40f}'.format(f))
print('{:.40f}'.format(d))
此代码的打印输出为:
0.8999999761581420898437500000000000000000
0.8999999999999999111821580299874767661094
如果我们在指定8到15个十进制数字的同时打印这两个值,那么我们将经历与您所观察到的相同的事情(double
值打印为0.9,而float
值打印接近0.9):
换句话说,这段代码:
for n in range(8,15 + 1):
string = '{:.' + str(n) + 'f}';
print(string.format(f))
print(string.format(d))
给出此打印输出:
0.89999998
0.90000000
0.899999976
0.900000000
0.8999999762
0.9000000000
0.89999997616
0.90000000000
0.899999976158
0.900000000000
0.8999999761581
0.9000000000000
0.89999997615814
0.90000000000000
0.899999976158142
0.900000000000000
因此,我们的结论是Java默认情况下会以8到15位之间的精度打印小数。
好问题BTW ...
本文链接:https://www.f2er.com/3168664.html