Source AN::Tools::Math: Difference between revisions
Jump to navigation
Jump to search
Created page with '{{mod_header}} <source lang="perl"> </source> {{footer}}' |
No edit summary |
||
(2 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
{{mod_header}} | {{mod_header}} | ||
'''[https://alteeve.ca/AN/Tools/Math.pm Math.pm]''' | |||
<source lang="perl"> | <source lang="perl"> | ||
package AN::Tools::Math; | |||
use strict; | |||
use warnings; | |||
our $VERSION="0.1.001"; | |||
my $THIS_FILE="Math.pm"; | |||
sub new | |||
{ | |||
my $class=shift; | |||
my $self={}; | |||
bless $self, $class; | |||
return ($self); | |||
} | |||
# Get a handle on the AN::Tools object. I know that technically that is a | |||
# sibling module, but it makes more sense in this case to think of it as a | |||
# parent. | |||
sub parent | |||
{ | |||
my $self=shift; | |||
my $parent=shift; | |||
$self->{HANDLE}{TOOLS}=$parent if $parent; | |||
return ($self->{HANDLE}{TOOLS}); | |||
} | |||
# This takes a number and rounds it to a given number of places after the | |||
# decimal (defaulting to an even integer). This does financial-type rounding. | |||
### MADI: Does this handle "x.95" type rounding properly? | |||
sub round | |||
{ | |||
my $self=shift; | |||
my $param=shift; | |||
# This just makes the code more consistent. | |||
my $an=$self->parent; | |||
# Clear any prior errors as I may set one here. | |||
$an->Alert->_set_error; | |||
# Setup my numbers. | |||
my $num=0; | |||
my $places=0; | |||
# Now see if the user passed the values in a hash reference or | |||
# directly. | |||
if (ref($param) eq "HASH") | |||
{ | |||
# Values passed in a hash, good. | |||
$num=$param->{number} ? $param->{number} : 0; | |||
$places=$param->{places} ? $param->{places} : 0; | |||
} | |||
else | |||
{ | |||
# Values passed directly. | |||
$num=$param; | |||
$places=defined $_[0] ? shift : 0; | |||
} | |||
# Make a copy of the passed number that I can manipulate. | |||
my $rounded_num=$num; | |||
# Take out any commas. | |||
$rounded_num=~s/,//g; | |||
# If there is a decimal place in the number, do the smart math. | |||
# Otherwise, just pad the number with the requested number of zeros | |||
# after the decimal place. | |||
if ( $rounded_num =~ /\./ ) | |||
{ | |||
# Split up the number. | |||
my ($real, $decimal)=split/\./, $rounded_num, 2; | |||
# If there is anything other than one ',' and digits, error. | |||
if (($real=~/\D/) || ($decimal=~/\D/)) | |||
{ | |||
$an->Alert->error({ | |||
fatal => 1, | |||
title => "Illegal value in 'AN::Tools::Math->round()'", | |||
message => "The passed real number: [$num] contains an illegal value. Only digits and one decimal place are allowed in the real number being rounded.", | |||
code => 2, | |||
file => "$THIS_FILE", | |||
line => __LINE__ | |||
}); | |||
# Return nothing in case the user is blocking fatal | |||
# errors. | |||
return (undef); | |||
} | |||
# If the number is already equal to the requested number of | |||
# places after the decimal, just return. If it's less, pad the | |||
# needed number of zeros. Otherwise, start rounding. | |||
if ( length($decimal) == $places ) | |||
{ | |||
# Equal, return. | |||
return $rounded_num; | |||
} | |||
elsif ( length($decimal) < $places ) | |||
{ | |||
# Less, pad. | |||
$rounded_num=sprintf("%.${places}f", $rounded_num); | |||
} | |||
else | |||
{ | |||
# Greater than; I need to round the number. Start by | |||
# getting the number of places I need to round. | |||
my $round_diff=length($decimal)-$places; | |||
# This keeps track of whether the next (left) digit | |||
# needs to be incremented. | |||
my $increase=0; | |||
# Now loop the number of times needed to round to the | |||
# requested number of places. | |||
for (1..$round_diff) | |||
{ | |||
# Reset 'increase'. | |||
$increase=0; | |||
# Make sure I am dealing with a digit. | |||
if ( $decimal =~ /(\d)$/ ) | |||
{ | |||
my $last_digit=$1; | |||
$decimal=~s/$last_digit$//; | |||
if ( $last_digit > 4 ) | |||
{ | |||
$increase=1; | |||
if ( $decimal eq "" ) | |||
{ | |||
$real++; | |||
} | |||
else | |||
{ | |||
$decimal++; | |||
} | |||
} | |||
} | |||
} | |||
if ( $places == 0 ) | |||
{ | |||
$rounded_num=$real; | |||
} | |||
else | |||
{ | |||
$rounded_num=$real.".".$decimal; | |||
} | |||
} | |||
} | |||
else | |||
{ | |||
# This is a whole number so just pad 0s as needed. | |||
$rounded_num=sprintf("%.${places}f", $rounded_num); | |||
} | |||
# Return the number. | |||
return ($rounded_num); | |||
} | |||
1; | |||
</source> | </source> | ||
{{footer}} | {{footer}} |
Latest revision as of 03:24, 5 May 2013
package AN::Tools::Math;
use strict;
use warnings;
our $VERSION="0.1.001";
my $THIS_FILE="Math.pm";
sub new
{
my $class=shift;
my $self={};
bless $self, $class;
return ($self);
}
# Get a handle on the AN::Tools object. I know that technically that is a
# sibling module, but it makes more sense in this case to think of it as a
# parent.
sub parent
{
my $self=shift;
my $parent=shift;
$self->{HANDLE}{TOOLS}=$parent if $parent;
return ($self->{HANDLE}{TOOLS});
}
# This takes a number and rounds it to a given number of places after the
# decimal (defaulting to an even integer). This does financial-type rounding.
### MADI: Does this handle "x.95" type rounding properly?
sub round
{
my $self=shift;
my $param=shift;
# This just makes the code more consistent.
my $an=$self->parent;
# Clear any prior errors as I may set one here.
$an->Alert->_set_error;
# Setup my numbers.
my $num=0;
my $places=0;
# Now see if the user passed the values in a hash reference or
# directly.
if (ref($param) eq "HASH")
{
# Values passed in a hash, good.
$num=$param->{number} ? $param->{number} : 0;
$places=$param->{places} ? $param->{places} : 0;
}
else
{
# Values passed directly.
$num=$param;
$places=defined $_[0] ? shift : 0;
}
# Make a copy of the passed number that I can manipulate.
my $rounded_num=$num;
# Take out any commas.
$rounded_num=~s/,//g;
# If there is a decimal place in the number, do the smart math.
# Otherwise, just pad the number with the requested number of zeros
# after the decimal place.
if ( $rounded_num =~ /\./ )
{
# Split up the number.
my ($real, $decimal)=split/\./, $rounded_num, 2;
# If there is anything other than one ',' and digits, error.
if (($real=~/\D/) || ($decimal=~/\D/))
{
$an->Alert->error({
fatal => 1,
title => "Illegal value in 'AN::Tools::Math->round()'",
message => "The passed real number: [$num] contains an illegal value. Only digits and one decimal place are allowed in the real number being rounded.",
code => 2,
file => "$THIS_FILE",
line => __LINE__
});
# Return nothing in case the user is blocking fatal
# errors.
return (undef);
}
# If the number is already equal to the requested number of
# places after the decimal, just return. If it's less, pad the
# needed number of zeros. Otherwise, start rounding.
if ( length($decimal) == $places )
{
# Equal, return.
return $rounded_num;
}
elsif ( length($decimal) < $places )
{
# Less, pad.
$rounded_num=sprintf("%.${places}f", $rounded_num);
}
else
{
# Greater than; I need to round the number. Start by
# getting the number of places I need to round.
my $round_diff=length($decimal)-$places;
# This keeps track of whether the next (left) digit
# needs to be incremented.
my $increase=0;
# Now loop the number of times needed to round to the
# requested number of places.
for (1..$round_diff)
{
# Reset 'increase'.
$increase=0;
# Make sure I am dealing with a digit.
if ( $decimal =~ /(\d)$/ )
{
my $last_digit=$1;
$decimal=~s/$last_digit$//;
if ( $last_digit > 4 )
{
$increase=1;
if ( $decimal eq "" )
{
$real++;
}
else
{
$decimal++;
}
}
}
}
if ( $places == 0 )
{
$rounded_num=$real;
}
else
{
$rounded_num=$real.".".$decimal;
}
}
}
else
{
# This is a whole number so just pad 0s as needed.
$rounded_num=sprintf("%.${places}f", $rounded_num);
}
# Return the number.
return ($rounded_num);
}
1;
Any questions, feedback, advice, complaints or meanderings are welcome. | |||
Alteeve's Niche! | Alteeve Enterprise Support | Community Support | |
© 2025 Alteeve. Intelligent Availability® is a registered trademark of Alteeve's Niche! Inc. 1997-2025 | |||
legal stuff: All info is provided "As-Is". Do not use anything here unless you are willing and able to take responsibility for your own actions. |