Dmi*_*try 4 floating-point perl
当我使用代码时:
(sub {
use strict;
use warnings;
print 0.49999999999999994;
})->();
Run Code Online (Sandbox Code Playgroud)
Perl输出"0.5".
当我从数字中删除一个"9"时:
(sub {
use strict;
use warnings;
print 0.4999999999999994;
})->();
Run Code Online (Sandbox Code Playgroud)
它打印0.499999999999999.
只有当我删除另外9个时,它才能准确地存储数字.
我知道,浮点数是蠕虫没有人愿意处理的也可以,但我很好奇,如果有在Perl的方式来"陷阱"这种隐式转换而不死,让我可以用eval捕获这种芯片,让用户知道Perl以其原生形式支持他们试图传递的号码(因此用户可以传递字符串或对象).
我需要这个的原因是为了避免传递0.49999999999999994被我的函数舍入的情况,但数字转换为0.5,然后舍入为1而不是0.我不知道如何"拦截"这个转换,以便我的函数"知道"它实际上没有得到0.5作为输入,但是用户的输入被截获.
如果不知道如何前拦截这种转换,我不能相信"圆圆",因为我不知道它是否收到了我输入我送了它,或者如果输入已经被修改(在编译时或运行时,不知道)的函数被调用(反过来,函数不知道它正在操作的输入是否是用户想要的输入,并且无法警告用户).
这不是Perl的独特问题,它发生在JavaScript中:
(() => {
'use strict';
/* oops: 1 */
console.log(Math.round(0.49999999999999999))
})();
Run Code Online (Sandbox Code Playgroud)
它发生在Ruby中:
(Proc.new {
# oops: 1
print (0.49999999999999999.round)
}).call()
Run Code Online (Sandbox Code Playgroud)
它发生在PHP中:
<?php
(call_user_func(function() {
/* oops: 1 */
echo round(0.49999999999999999);
}));
?>
Run Code Online (Sandbox Code Playgroud)
它甚至发生在C(这是可以发生的,但我的gcc并没有警告我数字没有精确存储(当指定特定的浮点文字时,最好准确存储它们,或者编译器应警告你它决定把它变成另一种形式(例如,"你的数目x不能在64位/ 32位浮点形式表示,所以其转换为y."),因此可以看到,如果这是正确的,或者不,在这种情况下,它是不)):
#include <math.h>
#include <stdio.h>
int main(int argc, char **argv)
{
/* oops: 1 */
printf("%f.\n", round(0.49999999999999999));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
摘要:
是否有可能在浮动数字的隐式转换中使Perl显示错误或警告,或者这是Perl5(以及其他语言)此时无法执行的操作(例如,编译器不会超出其支持的方式)这样的警告/提供一个标志来启用此类警告)?
例如
警告:数字0.49999999999999994无法表示,已被转换为0.5.使用bigint可能会解决这个问题.考虑降低数字的精确度.
也许使用BigNum:
$ perl -Mbignum -le 'print 0.49999999999999994'
0.49999999999999994
$ perl -Mbignum -le 'print 0.49999999999999994+0.1'
0.59999999999999994
$ perl -Mbignum -le 'print 0.49999999999999994-0.1'
0.39999999999999994
$ perl -Mbignum -le 'print 0.49999999999999994+10.1'
10.59999999999999994
Run Code Online (Sandbox Code Playgroud)
它透明地将Perl浮点和整数的精度扩展到扩展精度.