Skip Menu |

This queue is for tickets about the Number-Format CPAN distribution.

Report information
The Basics
Id: 75657
Status: new
Priority: 0/
Queue: Number-Format

People
Owner: Nobody in particular
Requestors: felix.ostmann [...] thewar.de
Cc:
AdminCc:

Bug Information
Severity: Wishlist
Broken in: (no value)
Fixed in: (no value)



Subject: Add new option: round_option (floor/ceil/normal)
This is exact the module i was locking for, but there was a feature missing: i want to decide what the rounding will do. Simple floor, ceil or the normal thing. Now here is a patch for that feature, but i am not sure if i understand your extra-feature with the "+ .5 + 1e-14". Would not POSIX::floor/ceil help in that solution? Perhaps my "1 - 1e-14" is also broken by design ... i dont know, but all tests are working and it was adobted from your code. Also i dont provide constants for the option, i am not sure if this is desired. Using < 0 for floor, == 0 for normal and > 0 for ceil looks very easy to understand and makes a constant needless.
Subject: Number-Format-1.73.roundoption.patch
diff -ru Number-Format-1.73/Format.pm Number-Format-1.73-roundoption/Format.pm --- Number-Format-1.73/Format.pm 2009-09-26 01:47:51.000000000 +0200 +++ Number-Format-1.73-roundoption/Format.pm 2012-03-09 22:55:13.838757462 +0100 @@ -24,7 +24,7 @@ $number = $x->unformat_number($formatted); use Number::Format qw(:subs); - $formatted = round($number, $precision); + $formatted = round($number, $precision, $roundoption); $formatted = format_number($number, $precision, $trailing_zeroes); $formatted = format_negative($number, $picture); $formatted = format_picture($number, $picture); @@ -59,6 +59,7 @@ DECIMAL_DIGITS - number of digits to the right of dec point (def 2) DECIMAL_FILL - boolean; whether to add zeroes to fill out decimal NEG_FORMAT - format to display negative numbers (def ``-x'') + ROUND_OPTION - decide to floor or normal rounding or ceil KILO_SUFFIX - suffix to add when format_bytes formats kilobytes (trad) MEGA_SUFFIX - " " " " " " megabytes (trad) GIGA_SUFFIX - " " " " " " gigabytes (trad) @@ -100,6 +101,7 @@ DECIMAL_DIGITS = 2 DECIMAL_FILL = 0 NEG_FORMAT = '-x' + ROUND_OPTION = 0 KILO_SUFFIX = 'K' MEGA_SUFFIX = 'M' GIGA_SUFFIX = 'G' @@ -127,6 +129,9 @@ C<format_number()> and C<format_price()> utilize this feature by calling C<format_negative()> if the number was less than 0. +C<ROUND_OPTION> is only used by C<round()>. A number less then 0 means +floor, a number bigger then 0 ceil and a 0 stand for a normal rounding. + C<KILO_SUFFIX>, C<MEGA_SUFFIX>, and C<GIGA_SUFFIX> are used by C<format_bytes()> when the value is over 1024, 1024*1024, or 1024*1024*1024, respectively. The default values are "K", "M", and @@ -195,7 +200,7 @@ $N_CS_PRECEDES $N_SEP_BY_SPACE $P_SIGN_POSN $N_SIGN_POSN ); our @EXPORT_OTHER = - qw( $DECIMAL_DIGITS $DECIMAL_FILL $NEG_FORMAT + qw( $DECIMAL_DIGITS $DECIMAL_FILL $NEG_FORMAT $ROUND_OPTION $KILO_SUFFIX $MEGA_SUFFIX $GIGA_SUFFIX $KIBI_SUFFIX $MEBI_SUFFIX $GIBI_SUFFIX ); @@ -242,6 +247,7 @@ our $DECIMAL_DIGITS = 2; our $DECIMAL_FILL = 0; our $NEG_FORMAT = '-x'; +our $ROUND_OPTION = 0; our $KILO_SUFFIX = 'K'; our $MEGA_SUFFIX = 'M'; our $GIGA_SUFFIX = 'G'; @@ -276,6 +282,7 @@ decimal_digits => $DECIMAL_DIGITS, decimal_fill => $DECIMAL_FILL, neg_format => $NEG_FORMAT, + round_option => $ROUND_OPTION, kilo_suffix => $KILO_SUFFIX, mega_suffix => $MEGA_SUFFIX, giga_suffix => $GIGA_SUFFIX, @@ -448,18 +455,25 @@ ##---------------------------------------------------------------------- -=item round($number, $precision) +=item round($number, $precision, $roundoption) Rounds the number to the specified precision. If C<$precision> is omitted, the value of the C<DECIMAL_DIGITS> parameter is used (default value 2). Both input and output are numeric (the function uses math operators rather than string manipulation to do its job), The value of -C<$precision> may be any integer, positive or negative. Examples: - - round(3.14159) yields 3.14 - round(3.14159, 4) yields 3.1416 - round(42.00, 4) yields 42 - round(1234, -2) yields 1200 +C<$precision> may be any integer, positive or negative. If C<$roundoption> +is omitted, the value of the C<ROUND_OPTION> paramter is used (default +value 0). Examples: + + round(3.14159) yields 3.14 + round(3.14159, undef, 1) yields 3.15 + round(3.14159, undef, -1) yields 3.14 + round(3.14159, 4) yields 3.1416 + round(42.00, 4) yields 42 + round(1234, -2) yields 1200 + round(1234, -2, 1) yields 1300 + round(1298, -2) yields 1300 + round(1298, -2, -1) yields 1200 Since this is a mathematical rather than string oriented function, there will be no trailing zeroes to the right of the decimal point, @@ -471,22 +485,29 @@ sub round { - my ($self, $number, $precision) = _get_self @_; - $precision = $self->{decimal_digits} unless defined $precision; - $precision = 2 unless defined $precision; - $number = 0 unless defined $number; - - my $sign = $number <=> 0; - my $multiplier = (10 ** $precision); - my $result = abs($number); - my $product = $result * $multiplier; + my ($self, $number, $precision, $roundoption) = _get_self @_; + $precision = $self->{decimal_digits} unless defined $precision; + $roundoption = $self->{round_option} unless defined $roundoption; + $precision = 2 unless defined $precision; + $roundoption = 0 unless defined $roundoption; + $number = 0 unless defined $number; + + my $sign = $number <=> 0; + my $multiplier = (10 ** $precision); + my $result = abs($number); + my $product = $result * $multiplier; + my $roundmodifier = $roundoption < 0 ? $sign < 0 ? 1 - 1e-14 : 0 + : $roundoption == 0 ? 0.5 + 1e-14 + : $roundoption > 0 ? $sign < 0 ? 0 : 1 - 1e-14 + : croak "impossible block" + ; croak "round() overflow. Try smaller precision or use Math::BigFloat" if $product > MAX_INT; # We need to add 1e-14 to avoid some rounding errors due to the # way floating point numbers work - see string-eq test in t/round.t - $result = int($product + .5 + 1e-14) / $multiplier; + $result = int($product + $roundmodifier) / $multiplier; $result = -$result if $sign < 0; return $result; } diff -ru Number-Format-1.73/t/round.t Number-Format-1.73-roundoption/t/round.t --- Number-Format-1.73/t/round.t 2009-05-05 22:53:31.000000000 +0200 +++ Number-Format-1.73-roundoption/t/round.t 2012-03-09 22:57:56.123562220 +0100 @@ -14,6 +14,21 @@ ok(compare_numbers(round(0), 0), 'identity 0'); ok(compare_numbers(round(1), 1), 'identity 1'); ok(compare_numbers(round(-1), -1), 'identity -1'); +ok(compare_numbers(round(1,0,-1), 1), 'floor 1'); +ok(compare_numbers(round(1,0, 0), 1), 'normal 1'); +ok(compare_numbers(round(1,0,+1), 1), 'ceil 1'); +ok(compare_numbers(round(-1,0,-1), -1), 'floor -1'); +ok(compare_numbers(round(-1,0, 0), -1), 'normal -1'); +ok(compare_numbers(round(-1,0,+1), -1), 'ceil -1'); +ok(compare_numbers(round(1.1,0,-1), 1), 'floor 1.1'); +ok(compare_numbers(round(1.1,0, 0), 1), 'normal 1.1'); +ok(compare_numbers(round(1.1,0,+1), 2), 'ceil 1.1'); +ok(compare_numbers(round(-1.1,0,-1), -2), 'floor -1.1'); +ok(compare_numbers(round(-1.1,0, 0), -1), 'normal -1.1'); +ok(compare_numbers(round(-1.1,0,+1), -1), 'ceil -1.1'); +ok(compare_numbers(round(-1.6,0,-1), -2), 'floor -1.6'); +ok(compare_numbers(round(-1.6,0, 0), -2), 'normal -1.6'); +ok(compare_numbers(round(-1.6,0,+1), -1), 'ceil -1.6'); ok(compare_numbers(round(PI,2), 3.14), 'pi prec=2'); ok(compare_numbers(round(PI,3), 3.142), 'pi prec=3'); ok(compare_numbers(round(PI,4), 3.1416), 'pi prec=4');