From 8c985a4419c28a779fb76abe5a404553a677a62b Mon Sep 17 00:00:00 2001
From: P. J. McDermott <pj@pehjota.net>
Date: Sat, 28 Jan 2017 15:01:43 -0500
Subject: dfmt(): New function

---
(limited to 'lib/Math/Decimal')

diff --git a/lib/Math/Decimal/FastPP.pm b/lib/Math/Decimal/FastPP.pm
index 538fb92..0f9960d 100644
--- a/lib/Math/Decimal/FastPP.pm
+++ b/lib/Math/Decimal/FastPP.pm
@@ -4,7 +4,7 @@ use strict;
 use warnings;
 
 use Exporter qw(import);
-our @EXPORT_OK = qw(dadd dmul drhtz drhfz);
+our @EXPORT_OK = qw(dadd dmul drhtz drhfz dfmt);
 
 our $VERSION = '0.001';
 
@@ -83,6 +83,21 @@ sub drhfz
 		substr($as, length($as) - $_[1]);
 }
 
+sub dfmt
+{
+	my ($a, $p) = @_;
+	my $s;
+	my $i;
+	my $f;
+	my $l;
+
+	($s, $i, $f) = $a =~ m/^(-?)(\d*).?(\d*)$/;
+	$l = length($f);
+	if ($i eq "") { $i = "0"; }
+	if ($l < $p) { $f .= "0" x ($p - $l); }
+	return $s . $i . "." . $f;
+}
+
 1;
 
 __END__
@@ -97,11 +112,12 @@ Math::Decimal::FastPP - Fast pure-Perl decimal math
 
 =head1 SYNOPSIS
 
-	use Math::Decimal::FastPP qw(dadd dmul drhtz drhfz);
+	use Math::Decimal::FastPP qw(dadd dmul drhtz drhfz dfmt);
 
 	$a = dadd($a, "1.23");  # $a += 1.23
 	$c = dmul($a, $b);      # $c = $a * $b
 	$a = drhtz($a);         # Round half toward zero
+	$a = dfmt($a, 2);       # Format with leading/trailing zeroes as needed
 
 =head1 DESCRIPTION
 
@@ -111,8 +127,8 @@ built-in binary floating-point math, but they're faster than
 L<Math::BigFloat|Math::BigFloat> and other commonly used decimal math modules.
 
 This module is currently less complete than Perl's built-in math and other
-decimal math modules.  So far it only includes addition, multiplication, and two
-rounding functions.
+decimal math modules.  So far it only includes addition, multiplication, two
+rounding functions, and one formatting function.
 
 Despite the similar name and purpose, this module is not compatible with
 L<Math::Decimal|Math::Decimal>.
@@ -133,9 +149,9 @@ zero" and "decimal round (away) from zero".
 =head1 THEORY
 
 The binary operation functions (C<dadd()> and C<dmul()>) operate on two numbers,
-C<a> and C<b>.  And obviously the unary operation functions (C<drhtz()> and
-C<drhfz()>) operate on one number, C<a>.  The binary operation functions produce
-a resulting number, C<c>.
+C<a> and C<b>.  And obviously the unary operation functions (C<drhtz()>,
+C<drhfz()>, and C<dfmt()>) operate on one number, C<a>.  The binary operation
+functions produce a resulting number, C<c>.
 
 The input numbers C<a> and C<b> are broken into their integer (C<i>) and
 fractional (C<f>) parts, for example C<$ai> and C<$af>.  All three numbers C<a>,
@@ -203,6 +219,26 @@ example:
 C<$p> is a non-negative (i.e. zero or positive) integer representing the number
 of significant digits right of the radix point.
 
+=head2 dfmt()
+
+	$a = dfmt($a, $p);
+
+Formats C<$a> with precision C<$p>.  Ensures that C<$a> has a leading zero if
+its absolute value is less than 1 and ensures that C<$a> has at least C<$p>
+digits in its fractional part.  For example:
+
+	dfmt("2.3", 2);  # Returns "2.30"
+	dfmt(".23", 2);  # Returns "0.23"
+
+C<$p> is a non-negative (i.e. zero or positive) integer representing the number
+of significant digits right of the radix point.
+
+The following two lines are equivalent, except that C<dfmt()> safely operates on
+C<$a> as a string instead of as a floating-point number:
+
+	$a = dfmt($a, $p);
+	$a = sprintf("%0.${p}f", $a);
+
 =head1 DIAGNOSTICS
 
 This module has no diagnostics.
@@ -226,10 +262,10 @@ L<Math::Decimal|Math::Decimal>.
 These arithmetic functions preserve all significant fractional digits, including
 trailing zeroes.  They also don't always add a leading zero before the radix
 point for numbers with absolute values less than one.  So the output numbers can
-look "ugly", like ".123000".  This is only an issue if the numbers (which are
-returned as strings) are concatenated into other strings or printed without
-formatting.  If this is an issue in your code, use the outputs as numbers (e.g.
-C<$c + 0>) or print with formatting (with C<printf>).
+look "ugly", like ".123000".  This is only an issue when the numbers (which are
+returned as strings) are concatenated into other strings or printed.  In these
+cases, you can round the numbers with C<drhtz()> or C<drhfz()> and format them
+with C<dfmt()>.
 
 =head1 AUTHOR
 
--
cgit v0.9.1