Source AN::Tools::Math

From Alteeve Wiki
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

 AN!Tools :: AN::Tools :: Source AN::Tools::Math

Math.pm

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! Enterprise Support:
Alteeve Support
Community Support
© Alteeve's Niche! Inc. 1997-2024   Anvil! "Intelligent Availability®" Platform
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.