在Perl中使用POSIX ceil()的意外结果 [英] Unexpected result using POSIX ceil() in Perl

查看:343
本文介绍了在Perl中使用POSIX ceil()的意外结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

 使用POSIX;我不知道为什么下面的结果会产生结果。 
my $ g = 6.65;
my $ t = $ g * 4;
my $ r = $ t - $ g;
my $ n = $ r / $ g;
my $ c = ceil($ n);
打印$ c($ n)\\\
;

标识,我知道 - 对不起。



 使用POSIX; 
my $ g = 6.65;
my $ t = $ g * 4;
my $ r = $ t - $ g;
my $ n = $ r / $ g;
my $ c = ceil($ n);
打印$ c($ n)\\\
;

...但我很困惑,为什么在这里需要。

解决方案

有些数字(如6.65)具有十进制的精确表示形式,但不能完全用计算机使用的二进制浮点表示(就像1 / 3没有确切的十进制表示)。因此,浮点数字通常与您所期望的稍有不同。您计算的结果不是3,而是大约3.000000000000000444.



处理这个问题的传统方法是定义一些小数字(称为epsilon),然后考虑两个数字如果它们的差异小于epsilon,那么它们是相等的。

ceil($ n)在将其转换为字符串时将浮点数转换为小数点后14位(从而将3.000000000000000444转换回3)。但是更快的解决方案是在计算 ceil 之前减去epsilon(因为 ceil 将四舍五入):

 我的$ epsilon = 5e-15; #或者任何你认为合适的小数字
my $ c = ceil($ n - $ epsilon);

浮点数减法应该比转换成字符串还要快(这涉及到很多除法)。


I can't for the life of me figure out why the following produces the result it does.

use POSIX;
my $g = 6.65;
my $t = $g * 4;
my $r = $t - $g;
my $n = $r / $g;
my $c = ceil($n);
print "$c ($n)\n";

Sigil-tastic, I know — sorry.

I've solved this for my app as follows:

use POSIX;
my $g = 6.65;
my $t = $g * 4;
my $r = $t - $g;
my $n = $r / $g;
my $c = ceil("$n");
print "$c ($n)\n";

...but I'm bewildered as to why that's necessary here.

解决方案

Some numbers (like 6.65) have an exact representation in decimal, but cannot be represented exactly in the binary floating point that computers use (just like 1/3 has no exact decimal representation). As a result, floating point numbers are frequently slightly different than what you would expect. The result of your calculation is not 3, but about 3.000000000000000444.

The traditional way of handling this is to define some small number (called epsilon), and then consider two numbers equal if they differ by less than epsilon.

Your solution of ceil("$n") works because Perl rounds a floating point number to around 14 decimal places when converting it to a string (thus converting 3.000000000000000444 back to 3). But a faster solution would be to subtract epsilon (since ceil will round up) before computing ceil:

my $epsilon = 5e-15; # Or whatever small number you feel is appropriate
my $c = ceil($n - $epsilon);

A floating point subtraction should be faster than converting to a string and back (which involves a lot of division).

这篇关于在Perl中使用POSIX ceil()的意外结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆