首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在打包和解包浮点数时消除浮点数的不准确性?

如何在打包和解包浮点数时消除浮点数的不准确性?
EN

Stack Overflow用户
提问于 2016-09-02 03:21:44
回答 3查看 253关注 0票数 3

我打包了一个数字数组,以便使用套接字编程通过UDP发送到另一个硬件。

当我pack数字12.2,然后unpack它,我得到12.199999892651。因为我使用的是与纬度和经度相关的数字,所以我不能有这样的偏差。

这是我写的简单脚本:

代码语言:javascript
运行
复制
use warnings;

use Time::HiRes qw (sleep);

@Data = ( 20.2, 30.23, 40.121, 1, 2, 3, 4, 6. 4, 3.2, 9.9, 0.1, 12.2, 0.99, 7.8, 999, 12.3 );

$myArr = pack('f*', @Data);

print "$myArr\n\n";

@Dec = unpack('f*',$myArr);

print "@Dec";

输出为:

代码语言:javascript
运行
复制
20.2000007629395 30.2299995422363 40.1209983825684 1 2 3 4 6.40000009536743 3.20 000004768372 9.89999961853027 0.100000001490116 12.1999998092651 0.9900000095367 43 7.80000019073486 999 12.3000001907349

有什么方法可以控制精度吗?

EN

回答 3

Stack Overflow用户

发布于 2016-09-02 03:47:53

packf模板是用于单精度浮点数的,在大多数平台上,它的精度可以达到7位小数左右,而d模板可以提供双精度,并且足以支持15位小数。

代码语言:javascript
运行
复制
print unpack("f", pack("f",12.2));          # "12.1999998092651"
print unpack("d", pack("d",12.2));          # "12.2"

printf "%.20f",unpack("f", pack("f",12.2)); # "12.19999980926513671875"
printf "%.20f",unpack("d", pack("d",12.2)); # "12.19999999999999928946"
票数 7
EN

Stack Overflow用户

发布于 2016-09-02 03:43:07

简短的答案是:不要将这些数字打包为浮点数。由于采用IEEE浮点表示法,您将失去准确性。相反,将它们转换为“字符小数”(即字符串),并将其打包为字符串。如果您确实需要精确度,并且不需要对它们执行数学运算,那么您可能还希望将它们存储为Perl中的字符串。

票数 4
EN

Stack Overflow用户

发布于 2016-09-02 12:09:18

2/10是二进制周期数,就像1/3是十进制周期数一样。它不可能准确地存储在浮点数中,因为它将占用无限的存储空间。

因此,并不是pack引入了错误;它准确地存储了您提供的数字。

代码语言:javascript
运行
复制
$ perl -E'say sprintf "%.20e", 12.2'
1.21999999999999992895e+01

$ perl -E'say sprintf "%.20e", unpack "d", pack "d", 12.2'
1.21999999999999992895e+01

只要你使用浮点数,你就不能准确地存储12.2。

但正如您在上面看到的,您可以使用d (双精度,接近16位精度)而不是f (单精度,超过7位精度)来存储足够精确的存储。Perl使用双精度,因此您实际上是通过使用f而不是d引入了精度损失。

因此,使用d,并对结果进行舍入(sprintf "%.10f")。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39279371

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档