处理货币价值,将数字除以100是否安全?

问题描述 投票:4回答:2

在存储库代码中,在另一个团队开发的模块中,我发现有一个价格从美分到欧元的转换,只是将数字除以100。

代码是Javascript,所以它使用IEEE 754标准。

我知道将货币值作为浮点数处理是不安全的,但我想知道在将任务发送给其他团队之前这个案例是否安全。

到目前为止,我没有发现任何将整数除以100得到不准确结果的情况。让我们走得更远:100就是2*2*5*5

我们知道将数字除以2是安全的,因为它只等于位置的移位。

所以我们可以很容易地说,如果存在一个不能被5整除的数字,则除以100是不准确的。

我做了很多测试,但我没有找到任何这些数字,但我还远远不是论文的理论论证。

那么,在IEEE 754标准中将数字除以100安全吗?

javascript ieee-754 ieee
2个回答
1
投票

具有15位有效精度的浮点十进制数转换为64位二进制浮点数(JavaScript中的Number)并返回到十进制而不会丢失精度。请注意,虽然二进制数可能不会精确地存储十进制数,但它具有更多的精度位数(表示它需要至少17位十进制有效数字)并且精确地将舍入转换回原始十进制数。有关详细信息,请参阅see https://www.exploringbinary.com/number-of-digits-required-for-round-trip-conversions/

当除以100时,二进制结果仍具有64位精度,并且可能以最小精度单位(manitissa的最低位)出现错误,除非结果下溢为0(有关完整详细信息,请参阅What Every Computer Scientist Should Know About Floating-Point Arithmetic)。仍然可以将舍入转换为15个有效十进制数字内的正确数字。

换句话说,如果您的十进制数字不超过15位有效数字,那么将它们除以100将保持该精度。

例如。在您的浏览器控制台中尝试123456789012345 / 1000.000123456789012345 / 100(这两个数字都有15位精确的十进制数字) - 这些除法在15位有效十进制数字内返回正确的十进制数字:

123456789012345 / 100
1234567890123.45

0.000123456789012345 / 100
0.00000123456789012345

0
投票

如果x是15十进制数字整数,则将x转换为JavaScript Number,除以100,并将结果转换为具有15个有效十进制数字的数字,恰好产生x / 100。证据如下。

笔记:

  • 将除法的结果转换为具有15个有效十进制数字的数字,恰好产生x / 100。分割的实际结果虽然是Number格式,但通常不会是x / 100。例如,73/100产生0.729999999999999982236431605997495353221893310546875。
  • 将除法的结果转换为超过15个有效十进制数字通常也不会产生x / 100,因为额外数字可能会显示差异,如上面的.73所示。 (当然,使用较少的数字可能不足以表示x / 100.)因此,如果希望将x / 100精确地传递给另一个进程,则必须使用恰好15个有效十进制数字(或其他一些缓解)为了错误)。
  • 以下证明适用于15位整数x,而不适用于其他15位有效小数位数字(例如带有15位十进制数字的数字后跟一个或多个零或数字,以小数点开头,后跟一些零后跟15有效数字)。

Preliminaries

JavaScript是ECMAScript的一种实现,在Ecma-262和ISO / IEC 16262中指定。在第6.1.6节中,Ecma-262规定IEEE-754基本64位二进制浮点格式用于ECMAScript的Number类型,但仅限于使用单个NaN。条款6.1.6进一步描述了所使用的算法,它基本上是IEEE-754算术,具有舍入到最近,连接到偶数。

IEEE-754基本64位二进制浮点格式使用53位有效数。

二进制浮点数的最小精度单位(ULP)是归因于其有效数中最低有效位的位置的值。 (因此,ULP与指数一起缩放。)在ULP中测量,所有正常的53位有效数都在[252 ULP,253 ULP]中。

对于15位有效十进制数,此处的ULP将是归因于从前导有效数字向下计数的第15位数位置的值。

Lemma

首先,我们建立一个众所周知的事实,即如果数字在Number格式的正常范围内,则将15位有效十进制数字转换为Number并返回到15位有效十进制数字会产生原始数字。

如果x是浮点格式(2-1022≤| x | <21024)的正常范围内的15个有效十进制数字(不一定是整数),则将x转换为浮点数中可表示的最接近的值 - 点格式,然后将结果转换为15个有效十进制数字恰好产生x,当两个转换都执行舍入到最接近,连接到偶数。要看到这一点,让y成为第一次转换的结果。如果y与x的差值小于x的ULP的1/2,则x是最接近y的15位有效数字,因此必须是第二次转换的结果。

在第一次转换中,由于舍入规则,结果y最多为x的1/2 ULP。这是至多1/2 / 252的相对精度(即,潜在的1/2 ULP误差除以有效数的最小值,可以在ULP中测量)。因此,y与x的不同之处在于253中最多一个部分。在最坏的情况下,x的数字可以是9999999999999 = 1015-1,因此相对于x的ULP的误差将是(1015-1)/ 253,其中大约是x的ULP的.111倍。因此,y总是与x的差值小于其ULP的1/2,因此将y转换回15个有效十进制数将产生x。

证明

如果x是一个15位十进制数的整数,它在Number格式中是完全可表示的,因为Number格式在其有效数字中有53位,因此能够精确地表示高达253的所有整数,即大约9.007e15,其中超过1015。

因此,将x转换为Number恰好产生x而没有错误。

然后,通过舍入算术结果的规则,将x除以100得到最接近x / 100的可表示数。叫这个y。现在请注意,x / 100是一个可用15位有效十进制数字表示的数字。 (它可以用科学记数法写成x•10-2或源代码中的数字x后缀为e-2。)注意,将x / 100转换为Number也会产生y,因为转换产生,就像分裂一样,Number格式中最接近x / 100的数字。通过引理,将x / 100转换为Number并返回到15-有效十进制数字的结果产生x / 100,因此将x转换为Number,然后除以100,然后转换为15显着的结果十进制数字也产生x / 100。

© www.soinside.com 2019 - 2024. All rights reserved.