你如何在Perl中使用浮点数?
我如何将十进制数(浮点数)四舍五入到最接近的整数?
例如
1.2 = 1 1.7 = 2
perldoc -q round
输出
Perl有一个round()函数吗? 那么ceil()和floor()呢? Trigfunction?
请记住,
int()
只是截断为0
。 为了舍入到一定数量的数字,sprintf()
或printf()
通常是最简单的路线。printf("%.3f", 3.1415926535); # prints 3.142
POSIX
模块(标准Perl分发的一部分)实现了ceil()
,floor()
以及其他一些math和三angular函数。use POSIX; $ceil = ceil(3.5); # 4 $floor = floor(3.5); # 3
在5.000至5.003 perls,在
Math::Complex
模块中进行三angular测量。 使用5.004时,Math::Trig
模块(标准Perl分布的一部分)实现了三angular函数。 它在内部使用Math::Complex
模块,一些函数可以从实轴分出到复平面,例如2的反正弦。财务申请的四舍五入可能会产生严重的影响,所使用的四舍五入方法应该被精确地指定。 在这些情况下,可能不会相信Perl正在使用的任何系统舍入,而是实现您自己需要的舍入函数。
为了明白为什么,注意你在半路点交替方面还有什么问题:
for ($i = 0; $i < 1.01; $i += 0.05) { printf "%.1f ",$i} 0.0 0.1 0.1 0.2 0.2 0.2 0.3 0.3 0.4 0.4 0.5 0.5 0.6 0.7 0.7 0.8 0.8 0.9 0.9 1.0 1.0
不要责怪Perl。 这和C一样。IEEE说我们必须这样做。 Perl数字的绝对值是
2**31
(在32位机器上)的整数将非常像math整数。 其他号码不能保证。
虽然不同意关于中途标记等的复杂答案,但对于更常见的(也可能是微不足道的)用例:
my $rounded = int($float + 0.5);
UPDATE
如果你的$float
可能是负值,下面的变化会产生正确的结果:
my $rounded = int($float + $float/abs($float*2 || 1));
用这个计算-1.4被四舍五入到-1,-1.6到-2,零不会爆炸。
你可以使用像Math :: Round这样的模块:
use Math::Round; my $rounded = round( $float );
或者你可以这样粗暴地做:
my $rounded = sprintf "%.0f", $float;
如果您决定使用printf或sprintf,请注意,他们使用Round half to even方法。
foreach my $i ( 0.5, 1.5, 2.5, 3.5 ) { printf "$i -> %.0f\n", $i; } __END__ 0.5 -> 0 1.5 -> 2 2.5 -> 2 3.5 -> 4
请参阅perldoc / perlfaq :
请记住,
int()
只是向0截断。为了舍入到一定数量的数字,sprintf()
或printf()
通常是最简单的路线。printf("%.3f",3.1415926535); # prints 3.142
POSIX
模块(标准的Perl发行版的一部分)实现了ceil()
,floor()
以及一些其他的math和三angular函数。use POSIX; $ceil = ceil(3.5); # 4 $floor = floor(3.5); # 3
在5.000至5.003 perls,在
Math::Complex
模块中进行三angular测量。使用5.004,
Math::Trig
模块(标准Perl分配的一部分)>实现三angular函数。它在内部使用
Math::Complex
模块,一些函数可以从实轴分出到复平面,例如2的反正弦。财务申请的四舍五入可能会产生严重的影响,所使用的四舍五入方法应该被精确地指定。 在这些情况下,可能不会相信Perl正在使用的任何系统舍入,而是实现您自己需要的舍入函数。
为了明白为什么,注意你在半路点交替方面还有什么问题:
for ($i = 0; $i < 1.01; $i += 0.05) { printf "%.1f ",$i } 0.0 0.1 0.1 0.2 0.2 0.2 0.3 0.3 0.4 0.4 0.5 0.5 0.6 0.7 0.7 0.8 0.8 0.9 0.9 1.0 1.0
不要责怪Perl。 这和C一样。IEEE说我们必须这样做。 Perl数字的绝对值是2 ** 31(在32位机器上)的整数将非常像math整数。 其他号码不能保证。
你不需要任何外部模块。
$x[0] = 1.2; $x[1] = 1.7; foreach (@x){ print $_.' = '.( ( ($_-int($_))<0.5) ? int($_) : int($_)+1 ); print "\n"; }
我可能会忽略你的观点,但我认为这是做同样工作的更简洁的方法。
它所做的是遍历元素中的每个正数,按照您提到的格式输出数字和四舍五入的整数。 该代码只能基于小数连接各自的舍入正整数。 int($ _)基本上将数字向下舍入,所以($ -int($ ))捕获小数。 如果小数(根据定义)严格小于0.5,则向下舍入数字。 如果不是,则加1。
负数可能会增加人们需要注意的一些怪癖。
printf
风格的方法给了我们正确的数字,但是它们会导致一些奇怪的显示。 我们发现这个方法(在我看来是愚蠢的)是否应该或不应该放入一个符号。 例如,-0.01四舍五入到小数点后一位将返回一个-0.0,而不是仅为0.如果您要执行printf
样式方法,并且您知道不需要小数,请使用%d
而不是%f
(当您需要小数点,这是当显示变得怪异)。
虽然这是正确的和math没什么大不了的,为显示它看起来很奇怪,显示像“-0.0”的东西。
对于int方法,负数可以改变你想要的结果(虽然有一些参数可以使它们是正确的)。
int + 0.5
引起真正的问题 – 负数,除非你想这样工作,但我想大多数人不这样做。 -0.9应该可以舍入为-1,而不是0.如果你知道你希望消极的是一个天花板,而不是一个地板,那么你可以做到一行,否则,你可能想要用int方法修改(这显然只适用于取回整数:
my $var = -9.1; my $tmpRounded = int( abs($var) + 0.5)); my $finalRounded = $var >= 0 ? 0 + $tmpRounded : 0 - $tmpRounded;
我的解决schemesprintf
if ($value =~ m/\d\..*5$/){ $format =~ /.*(\d)f$/; if (defined $1){ my $coef = "0." . "0" x $1 . "05"; $value = $value + $coef; } } $value = sprintf( "$format", $value );
以下将把正数或负数舍入到给定的小数位:
sub round () { my ($x, $pow10) = @_; my $a = 10 ** $pow10; return (int($x / $a + (($x < 0) ? -0.5 : 0.5)) * $a); }
以下是五种不同的总结数值的方法的示例。 首先是一个天真的方式来执行总结(和失败)。 第二次尝试使用sprintf()
,但也失败了。 第三个使用sprintf()
成功,而最后两个(第四和第五个)使用floor($value + 0.5)
。
use strict; use warnings; use POSIX; my @values = (26.67,62.51,62.51,62.51,68.82,79.39,79.39); my $total1 = 0.00; my $total2 = 0; my $total3 = 0; my $total4 = 0.00; my $total5 = 0; my $value1; my $value2; my $value3; my $value4; my $value5; foreach $value1 (@values) { $value2 = $value1; $value3 = $value1; $value4 = $value1; $value5 = $value1; $total1 += $value1; $total2 += sprintf('%d', $value2 * 100); $value3 = sprintf('%1.2f', $value3); $value3 =~ s/\.//; $total3 += $value3; $total4 += $value4; $total5 += floor(($value5 * 100.0) + 0.5); } $total1 *= 100; $total4 = floor(($total4 * 100.0) + 0.5); print '$total1: '.sprintf('%011d', $total1)."\n"; print '$total2: '.sprintf('%011d', $total2)."\n"; print '$total3: '.sprintf('%011d', $total3)."\n"; print '$total4: '.sprintf('%011d', $total4)."\n"; print '$total5: '.sprintf('%011d', $total5)."\n"; exit(0); #$total1: 00000044179 #$total2: 00000044179 #$total3: 00000044180 #$total4: 00000044180 #$total5: 00000044180
请注意, floor($value + 0.5)
可以用int($value + 0.5)
replace,以消除对POSIX
的依赖。
如果您只关心从整个浮点数(即12347.9999或54321.0001)中获取一个整数值,则此方法(借用并从上面修改)将执行此操作:
my $rounded = floor($float + 0.1);
cat table | perl -ne '/\d+\s+(\d+)\s+(\S+)/ && print "".**int**(log($1)/log(2))."\t$2\n";'