Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/87.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Perl sprintf:定点、大数字和精度损失_Perl_Floating Point_Printf_Fixed Point - Fatal编程技术网

Perl sprintf:定点、大数字和精度损失

Perl sprintf:定点、大数字和精度损失,perl,floating-point,printf,fixed-point,Perl,Floating Point,Printf,Fixed Point,我需要读取数据库中的一些数字,并使用Perl将它们写入文本文件 在数字所在的表格中,数据格式定义为数字(25,5)(读取25位数字,包括5位小数) 我使用sprintf“%.5f”、$myvalue对文件中的数字进行格式化,强制使用5位小数,我刚刚注意到,对于大数值,超过17位的数字会丢失精度: db = 123.12345 file = 123.12345 (OK) db = 12345678901234891.12345 file = 12345678901234892.00000

我需要读取数据库中的一些数字,并使用Perl将它们写入文本文件

在数字所在的表格中,数据格式定义为
数字(25,5)
(读取25位数字,包括5位小数)

我使用
sprintf“%.5f”、$myvalue
对文件中的数字进行格式化,强制使用5位小数,我刚刚注意到,对于大数值,超过17位的数字会丢失精度:

db   = 123.12345
file = 123.12345 (OK)

db   = 12345678901234891.12345
file = 12345678901234892.00000 (seems to be rounded to upper integer)

db   = 12345678901234567890.12345
file = 12345678901234567000.00000 (truncation ?)
Perl对于固定小数的最大精度是什么

一般来说,我知道浮点运算的概念和局限性,但我不是Perl僧侣,我不知道Perl的内部结构,所以我不知道它是否正常(或者它是否与浮点相关)。我不确定这是Perl的内部限制,还是与
sprintf
处理相关的问题

是否有解决方法或专用模块可以帮助解决该问题

值得注意的是:

  • 这是已经使用Perl的系统的一个附加功能,因此不能使用其他工具
  • 正在处理的数据是财务数据,因此我需要保留每一分钱,我无法处理+/-10000个单位的精度:^S
Perl对于固定小数的最大精度是什么


Perl没有固定的小数点。实际上,很少有语言能做到这一点。你可以使用这样一个模块,尽管再次强调,我在询问之后马上找到了一个解决方案。我将我的解决方案放在这里,以帮助未来的访问者:

替换

$myout = sprintf "%.5f", $myvalue;


没有像Math::BigFloat这样的模块,16位以上的所有东西都是纯粹的魔法。。。e、 g

perl -e 'printf "*10^%02d: %-.50g\n", $_, log(42)*(10**$_) for (0..20)'
产生

*10^00: 3.7376696182833684112267746968427672982215881347656
*10^01: 37.376696182833683224089327268302440643310546875
*10^02: 373.76696182833683224089327268302440643310546875
*10^03: 3737.6696182833684360957704484462738037109375
*10^04: 37376.6961828336861799471080303192138671875
*10^05: 373766.96182833681814372539520263671875
*10^06: 3737669.6182833681814372539520263671875
*10^07: 37376696.18283368647098541259765625
*10^08: 373766961.82833683490753173828125
*10^09: 3737669618.283368587493896484375
*10^10: 37376696182.83368682861328125
*10^11: 373766961828.33685302734375
*10^12: 3737669618283.36865234375
*10^13: 37376696182833.6875
*10^14: 373766961828336.8125
*10^15: 3737669618283368.5
*10^16: 37376696182833688
*10^17: 373766961828336832
*10^18: 3737669618283368448
*10^19: 37376696182833684480
*10^20: 373766961828336828416

Perl在内部将值存储为浮点数。1精度取决于Perl版本的编译方式,但可能是64位双精度

C:\>perl -MConfig -E "say $Config::Config{doublesize}"
8
64位双精度浮点2的有效位为53位(也称为分数或尾数),其精度约为16个十进制字符。您的数据库定义为存储25个精度字符。如果您将数据视为字符串,您会很好,但如果您将其视为数字,您将失去精度

Perl的
bignum
pragma为任意大的数字提供了透明的支持。它可以大大降低速度,从而将其使用限制在尽可能小的范围内。如果您只需要大浮点(而不需要将其他数值类型设置为“大”),请使用
Math::BigFloat

1.在内部,perl使用一种称为SV的数据类型,它可以同时保存浮点、整数和/或字符串。
2.假设IEEE 754格式。

或者,如果您只是将值从数据库传输到文本文件,而不是将其作为数字进行操作,则让DB将其格式化为字符串。然后将它们作为字符串读取并打印(可能使用“printf“%s”)。例如:

select Big_fixed_point_col(format '-Z(24)9.9(5)')(CHAR(32))

这是过早的优化吗?为什么您觉得需要“强制”5位小数?也许可以帮助您?当您将字符串写入文本文件时,您并不是在优化。@choroba我在想,它似乎至少能够正确打印数字。@TLP:这只是需要的输出。不确定是否有实际和客观原因,文件将在以后自动处理,而不是直接由人使用。而
Math::BigFloat
确实有帮助,我在问了我的问题后发现了这一点。因此,在Perl中,十进制值的内部表示实际上是一个float?@Seki,是的。(实际上是双精度的,可能是四精度的)@ikegami 123456789012134892是最接近1234567890134891.12345的IEEE 754 64位二进制值,表示是双精度的。@Patricia Shanahan,这对所有版本都不一样。Per使用双精度,可能使用四精度。
select Big_fixed_point_col(format '-Z(24)9.9(5)')(CHAR(32))