2

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

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

我用 a 格式化文件中的数字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 的系统的附加功能,因此不能选择使用其他工具
  • 被处理的数据是财务数据,所以我需要保留每一分钱,我无法应对 +/- 10 000 单位的精度:^S
4

5 回答 5

2

再一次,我在询问 SO 后立即找到了解决方案。我将我的解决方案放在这里,以帮助未来的访客:

代替

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

经过

use Math::BigFloat;
$myout = Math::BigFloat->new($myvalue)->ffround( -5 )->bstr;
于 2013-07-25T11:57:24.873 回答
2

如果没有像 Math::BigFloat 这样的模块,16 位以上的所有内容都是纯粹的魔法......例如

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
于 2013-07-25T12:11:34.673 回答
1

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

C:\>perl -MConfig -E "say $Config::Config{doublesize}"
8

一个 64 位双精度浮点数2有一个 53 位有效数(又名小数或尾数),它提供了大约 16 个十进制字符的精度。您的数据库被定义为存储 25 个精确字符。如果您将数据视为字符串,您会很好,但如果您将其视为数字,您将失去精度。

Perl 的bignumpragma 为任意大的数字提供透明的支持。它可以大大减慢速度,因此将其使用限制在尽可能小的范围内。如果您只想要大浮点数(而不使其他数字类型“大”) ,请Math::BigFloat改用。

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

于 2013-07-25T16:19:32.830 回答
1

Perl 对于固定十进制数的最大精度是多少?

Perl 没有定点十进制数。实际上,很少有语言可以做到。不过,您可以使用像Math::FixedPoint这样的模块

于 2013-07-25T11:54:45.817 回答
0

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

select Big_fixed_point_col(format '-Z(24)9.9(5)')(CHAR(32))
于 2016-03-03T20:12:41.240 回答