在Perl中舍入浮点数



我必须将MySQL查询的结果四舍五入。我没有找到一个很好的解决方案,以正确的方式四舍五入(在我看来,截断不是正确的方式)。

我编写了这段代码,对浮点数进行舍入,并以西班牙-墨西哥的方式对数字进行格式化(使用逗号作为千,百万等)。(如1425年→1425)

我知道它效率很低,但它的工作方式是正确的。如果您有任何建议,请告诉我,以使其更有效。

为西班牙语变量和注释感到抱歉。我是墨西哥! !;)

sub formatea_numero                 # recibe una cifra sin formato y le agrega comas por cada 3 digitos
{
my($importe_orig,$dec_a_redondear) = @_;
my @digitos_corregido;
my $contador=0;
my $signo;
my $importex;
my $decimal_con_ceros_al_inicio = 0;
### SIGNO ######################
### Obteniendo el signo si lo tiene
if($importe_orig=~/([-|+])(.*)/)    # SI TIENE SIGNO $1 EL NUM ES $2
{
$signo = $1;
$importex = substr $importe_orig, 1;
}
else                                # NO TIENE SIGNO EL NUM ES $importe_orig
{
$importex = $importe_orig;
}

###  DECIMALES ################
### Si tiene decimales.. se obtiene la parte entera y la parte decimal
if($importex=~/./)     # Tiene decimales
{   
if ($dec_a_redondear ne "" && $dec_a_redondear == 0)    # Caso Especial de que son 0 decimales a redondear
{
$importex=~/(.*).(.)(.*)/;
$parte_entera = $1;
$primer_decimal = $2;
$resto_decimal = $3;
if ($primer_decimal >= 5)
{$parte_entera = $parte_entera+1;}          
}
else
{

if($importex=~/(.*).(.+)/)     # Parte entera $1  Parte decimal $2
{
$parte_entera = $1;
$parte_decimal = $2;
if ($parte_decimal=~/^(0+).*/ ) # Caso especial si el decimal inicia en 0  ejem 3.0015 1.0000003  1.04  etc
{
$decimal_con_ceros_al_inicio =1;
$parte_decimal = "1" . $parte_decimal;
}           
}

########### REDONDEAR DECIMALES 

if ($decimal_con_ceros_al_inicio)
{   
$dec_a_redondear =  1 + $dec_a_redondear;
$num_decimales_original = 1+ length $parte_decimal;
}
else
{   $num_decimales_original = length $parte_decimal;}

if ($dec_a_redondear>=0 && $dec_a_redondear < $num_decimales_original)
{

$parte_decimal_1 = substr($parte_decimal,0,$dec_a_redondear);   # se obtienen los digitos hasta el numero de decimales que se quiere redondear
$siguiente_decimal = substr($parte_decimal,$dec_a_redondear,1); # se obtiene el primer dígito a descartar .. si es mayor que 5 se le agrega uno al anterior digito

if($siguiente_decimal >=5)
{
$largo_inicial_parte_decimal_1 = length $parte_decimal_1;           
$parte_decimal_1 = $parte_decimal_1 +1;
$largo_final_parte_decimal_1 = length $parte_decimal_1;
if($largo_final_parte_decimal_1 <= $largo_inicial_parte_decimal_1)
{
$parte_decimal = $parte_decimal_1;
}
else
{
$parte_entera = $parte_entera + 1;
$parte_decimal = $parte_decimal_1 - 1;
$parte_decimal = 0;
}
}
else
{
$parte_decimal = $parte_decimal_1;
}


} # cierra if ($dec_a_redondear>0 && $dec_a_redondear < $num_decimales_original)
if ($decimal_con_ceros_al_inicio)
{   
$parte_decimal=~/^1(.+)/;
$parte_decimal = $1;
}

########### TERMINA DECIMALES (redondeando) 
}   # Cierra if ($dec_a_redondear ne "" && $dec_a_redondear == 0)   # Caso Especial de que son 0 decimales a redondear

} # cierra  if($importex=~/./)     # Tiene decimales
########### FORMATEANDO LOS MILES ###########
if($importex=~/./)     # Tiene decimales
{       
@digitos = split(//,$parte_entera);
}
else                    # No tiene decimales
{
@digitos = split(//,$importex);
}
@digitos= reverse(@digitos);    

foreach $digito(@digitos)
{   
if ($contador ==3)
{
push (@digitos_corregido,",");
push (@digitos_corregido,$digito);
$contador=1;
}
else
{
push (@digitos_corregido,$digito);
$contador++;
}
}

@digitos_corregido = reverse(@digitos_corregido);
$importe2 = join('',@digitos_corregido);
### Termina de procesar la parte entera 


### Se integra el signo, la parte entera formateada y la parte decimal
if($importex=~/./)
{
if ($dec_a_redondear ne "" && $dec_a_redondear == 0)
{   $importe2 = $importe2;}
else
{   
if ($parte_decimal >0)
{$importe2 = $importe2 . "." .$parte_decimal;}
else
{$importe2 = $importe2;}
}
}
if($importe_orig=~/([-|+])(.*)/)
{
$importe2 = $signo . $importe2 ;        
}
return $importe2;
} # cierra sub formatea_numero                  # recibe una cifra sin formato y le agrega comas por cada 3 digitos

这似乎是很多代码四舍五入的数字。我不能完全理解西班牙语的所有细节,但如果你没有特殊的标准,那么基本的就足够了,用sprintf

$num = sprintf "%.2f", $num  if $num =~ /./;

(这将把.00加到一个整数上,所以我的条件是有.。它最好是一个合法的数字。)

sprintf使用四舍五入的一半到偶数,根据IEEE754四舍五入到最接近的(整数)关系到偶数规则。(Windows可能会有所不同,因为它不尊重IEEE规范,但Strawberry Perl确实round to even,感谢ikegami的注释。)

也有图书馆,喜欢数学:圆形或数学::BigFloat。请仔细研究这个主题,特别是如果您的应用程序对细节很敏感(比如金融或科学应用程序),因为使用浮点数的工作充满了棘手的问题。另见perlfaq4 on舍入(etc)

然后可以添加&;thousand separators &;(根据需要使用,),通过从后面(在子字符串中直到小数点)将每个数字三元组替换为逗号+本身。最好在子目录

中换行
sub commify {
local $_ = shift;  
1 while s/^([-+]?[0-9]+)([0-9]{3})/$1,$2/;   
return $_;
}

参见perlfaq5查看更多

最新更新