Number::WithError(3)
๐ Number::WithError ๐
okay so bestie, you're reading the manual page for Number::WithError(3) from the User Contributed Perl Documentation and honestly? it's giving โจ*math but make it rigorous*โจ. let's get into it.
โจ NAME โจ
Number::WithError โ numbers that carry their own errors around, and do scientific rounding on top. that's it, that's the whole vibe. ๐
โจ SYNOPSIS โจ
okay look at this, it's literally so satisfying:
use Number::WithError;
my $num = Number::WithError->new(5.647, 0.31);
print $num . "\n";
# prints '5.65e+00 +/- 3.1e-01'
# (I.e. it automatically does scientific rounding)
my $another = $num * 3;
print $another . "\n";
# propagates the error assuming gaussian errors
# prints '1.69e+01 +/- 9.3e-01'
# trigonometric functions also work:
print sin($another) . "\n";
# prints '-9.4e-01 +/- 3.1e-01'
my $third = $another ** $num;
print $third. "\n";
# propagates both errors into one.
# prints '8.7e+06 +/- 8.1e+06'
# shortcut for the constructor:
use Number::WithError 'witherror';
$num = witherror('0.00032678', ['2.5e-5', '3e-5'], 5e-6);
# can deal with any number of errors, even with asymmetric errors
print $num . "\n";
# prints '3.268e-04 + 2.5e-05 - 3.00e-05 +/- 5.0e-06'
# Note: It may be annyoing that they don't all have the same
# exponent, but they *do* all have the sam significant digit!
the way that last comment is spelled is honestly so real of it. no cap. ๐ญ
โจ DESCRIPTION โจ
so this class is a container class for numbers that come with a bunch of attached symmetric and asymmetric errors. it overloads basically all the common arithmetic operations and trig functions so the errors propagate for you automatically. it also does proper scientific rounding โ the whole explanation lives down in the docs for the significant_digit() method. ๐
you can also use Math::BigFloat objects as the internal representation of your numbers, if you want arbitrary-precision calculations. main character energy, honestly. ๐
errors propagate using Gaussian error propagation. that's the rule of the land. ๐ง
okay and here's a fun fact: with one notable exception, the test suite covers way over ninety percent of the code. the remaining holes are mostly difficult-to-test corner cases and sanity tests. the exception? the comparison routines โ those are getting more extensive tests in a future release. so like, just be aware. ๐ซถ
โจ OVERLOADED INTERFACE โจ
this module uses overload so you can use ordinary Perl arithmetic operators right on your objects, no ->method needed. but also โ every overloaded operation is also available via methods. here's the full list of overloaded operators and their equivalent methods:
- Addition:
$x + $yis implemented by the$x->add($y)method. - Increment:
$x++is implemented by the$x->add(1)method. - Subtraction:
$x - $yis implemented by the$x->subtract($y)method - Decrement:
$x--is implemented by the$x->subtract(1)method. - Multiplication:
$x * $yis implemented by the$x->multiply($y)method. - Division:
$x / $yis implemented by the$x->divide($y)method. - Exponentiation:
$x ** $yis implemented by the$x->exponentiate($y)method. - Sine:
sin($x)is implemented by the$x->sin()method. - Cosine:
cos($x)is implemented by the$x->cos()method. - Stringification
$xis implemented by the$x->round()method. - Cast to a number (i.e. numeric context) is implemented by the
$x->number()method. - Boolean context is implemented by the
$x->number()method. - Unary minus
-$xis implemented by the$x->multiply(-1)method. - Logical not is implemented via a boolean context.
- Absolute value
abs($x)is implemented via$x->abs(). - Natural logarithm
log($x)is implemented via$x->log(). - Square Root
sqrt($x)is implemented via$x->sqrt(). - Numeric comparison operators
$x == $y,$x != $y, etc. are implemented via$x->numeric_cmp($y). - String comparison operators
$x eq $y,$x ne $y, etc. are implemented via$x->full_cmp($y). They might not do what you expect. Please read the documentation.
also: the assignment forms of arithmetic operators (like +=) are available if their normal counterpart is overloaded. so like, they come as a package deal. ๐
and here's a list of overloadable operations that are not overloaded in the context of this module:
<< >> x . & ^ | atan2 int
not invited to the party, sorry babes. ๐
โจ CONSTRUCTORS โจ
heads up: all constructors accept Math::BigFloat objects in place of numbers. ๐ฆ
new
this is the basic constructor for Number::WithError objects.
new objects can be created in one of two ways:
- The first argument is expected to be the number itself. Then come zero or more errors. Errors can either be a number, a reference to an array of two numbers, or
undef. In the former case, the number is treated as an uncertainty which has the same magnitude in both directions. (I.e.+/- x) In case of an array reference, the first number is treated as the upper error boundary and the second as the lower boundary. (I.e.+x, -y)undefis treated as zero error. - The second way to create objects is passing a single string to the constructor which is efficiently parsed into a number and any number of errors. I'll explain the format with an example:
133.14e-5 +/- .1e-4 + 0.00002 - 1.0e-5 +/- .2e-4
In this example, the first number is parsed as the actual number. The following number is treated as a symmetric error (.1e-4). The two following numbers are treated as the upper and lower boundary for a single error. Then comes another ordinary error. It is also legal to define the lower boundary of an error before the upper boundary. (I.e. -1.0e-5 +0.00002)
Whitespace is insignificant. yes bestie, you can space it however you want, it does not care. ๐
For the sake of completeness, I'll mention the regular expression that is used to match numbers. It's taken from the official Perl FAQ to match floating point numbers:
[+-]?(?=\d|\.\d)\d*(?:\.\d*)?(?:[Ee][+-]?\d+)?
Don't worry if you don't understand it. Just run a few tests to see if it'll accept your numbers. Or go read perldoc -q float or pick up a book on C and read up on how they define floating point numbers.
โ ๏ธ Note that trailing zeros currently have no effect. (Yes, this is a BUG!) like, it's literally marked as a bug in the source. iconic of it, honestly. ๐
The constructor returns a new object of this class or undef if something went wrong.
new_big
this is an alternative constructor for Number::WithError objects. it works exactly like new except that it makes all internal numbers instances of Math::BigFloat for high precision calculations. โจ
The module does not load Math::BigFloat at compile time to avoid loading a big module that isn't needed all the time. Instead, this module makes use of the prefork pragma and loads Math::BigFloat when needed at run-time. efficient queen behavior. ๐
witherror
this constructor is not a method. it is a subroutine that can be exported to your namespace on demand. it works exactly as the new() method except it's a subroutine and shorter. shorter = slay. ๐
I'm normally not for this kind of shortcut in object-oriented code, but if you have to create a large number of Number::WithError numbers, you'll appreciate it. Trust me. ๐ซถ
๐ Note to authors of subclasses: If you inherit from this module, you'll need to implement your own witherror() because otherwise, it will still return objects of this class, not your subclass. so like, do not skip this step bestie, it will not do what you think. ๐ญ
witherror_big
this is also not a method. it does the same as witherror(). it can also be optionally be exported to your namespace.
It uses the new_big constructor instead of the new constructor used by witherror().
โจ ARITHMETIC METHODS โจ
okay so, important: all of these methods implement an arithmetic operation on the object and the method's first parameter.
The methods aren't mutators. That means they don't modify the object itself, but return the result of the operation as a new object. your original stays pristine, as she should. ๐
All of the methods accept either a plain number, a Number::WithError object or anything that is understood by the constructors as argument,
All errors are correctly propagated using Gaussian Error Propagation. The formulae used for this are mentioned in the individual methods' documentation. ๐งฎ
add
Adds the object a and the argument b. Returns a new object c.
Formula: c = a + b
Error Propagation: err_c = sqrt( err_a^2 + err_b^2 )
subtract
Subtracts the argument b from the object a. Returns a new object c.
Formula: c = a - b
Error Propagation: err_c = sqrt( err_a^2 + err_b^2 )
multiply
Multiplies the object a and the argument b. Returns a new object c.
Formula: c = a * b
Error Propagation: err_c = sqrt( b^2 * err_a^2 + a^2 * err_b^2 )
divide
Divides the object a by the argument b. Returns a new object c.
Formula: c = a / b
Error Propagation: err-c = sqrt( err_a^2 / b^2 + a^2 * err_b^2 / b^4 )
exponentiate
Raises the object a to the power of the argument b. Returns a new object c. Returns undef if a is negative because the error cannot be propagated in that case. (Can't take log of a negative value.)
Also, please have a look at the error propagation formula below. Exponentiation and logarithms are operations that can become numerically unstable very easily. so like, tread carefully, bestie. ๐ธ
Formula: c = a ^ b
Error Propagation: err-c = sqrt( b^2 * a^(b-1) * err_a^2 + ln(a)^2 * a^b * err_b^2 )
โจ METHODS FOR BUILTIN FUNCTIONS โจ
these methods calculate functions of the object and return the result as a new object. no mutation, just vibes. ๐ฆ
sqrt
Calculates the square root of the object a and returns the result as a new object c. Returns undef if a is negative.
Formula: c = sqrt(a)
Error Propagation: err-c = sqrt( err-a^2 / (2*sqrt(a))^2 ) = abs( err-a / (2*sqrt(a)) )
log
Calculates the natural logarithm of an object a. Returns a new object c. If a is negative, the function returns undef.
Formula: c = log(a)
Error Propagation: err-c = sqrt( err-a^2 / a^2 ) = abs( err-a / a )
sin
Calculates the sine of the object a and returns the result as a new object c.
Formula: c = sin(a)
Error Propagation: err-c = sqrt( cos(a)^2 * err-a^2 ) = abs( cos(a) * err-a )
cos
Calculates the cosine of the object a and returns the result as a new object c.
Formula: c = cos(a)
Error Propagation: err-c = sqrt( sin(a)^2 * err-a^2 ) = abs( sin(a) * err-a )
tan
Calculates the tangent of the object a and returns the result as a new object c.
Formula: c = tan(a)
Error Propagation: err-c = sqrt( err-a^2 / cos(a)^4 ) = abs( err-a / cos(a)^2 )
Since there is no built-in tan() function, this operation is not available via the overloaded interface. so you have to call it as a method. just so you know. ๐
abs
Calculates the absolute value of an object a. Leaves the errors untouched. Returns a new object c.
Formula: c = abs(a)
Error Propagation: err-c = err-a
โฆand that's where part 1 of this page wraps up, bestie โ more is coming. ๐โจ
โจ ROUNDING, STRINGIFICATION AND OUTPUT METHODS โจ
okay bestie this whole section is about getting stuff back out of your object โ like, all the ways to pull data out, round it, turn it into a string, and peek at the meta info (hi, significant digit ๐).
๐ธ number
Determines the significant digit using the significant_digit() method, rounds the number that the object number() is called on represents to that digit, and hands you back the rounded number.
And here's the tea: no matter what the internal representation of the number is, this returns an unblessed string / an unblessed floating point number. Like, it's raw. It's free. It's not an object anymore.
If you want access to the raw number representation still chilling inside the object, use the "raw_number" method instead.
Either way, the number comes out in scientific notation โ meaning the first non-zero digit sits before the decimal point, and after the decimal point you get any number of digits, then an exponent in "eXXX" notation. periodt. ๐
๐ฆ raw_number
This one returns the internal representation of the number in the object. It does not round as appropriate. It does not clone Math::BigFloat objects either. So make sure you do that yourself if you need it!!
โ ๏ธ no clone = shared vibes. if you mutate it, you mutate the original. be careful bestie.
๐ round
This method figures out the significant digit using the significant_digit() method. Then it rounds the number represented by the object and all associated errors to that digit.
Then it concatenates the number with its errors and returns the resulting string. Here's how the errors get dressed up:
- symmetric errors โ the string
"+/-"gets prepended to the error - asymmetric errors โ a
"+"gets prepended to the first/upper error component, and a"-"to the second/lower error component
Returns the previously described string. ๐
๐ง significant_digit
Returns the significant digit of the number it's called on, as an integer. But plot twist: if the number has no errors, or all errors are "undef" or zero, this method returns "undef".
How to read the return value, bestie:
- returns
-5โ the significant digit is"1 * 10**-5"or0.00001 - returns
3โ the significant digit is"1 * 10**3"or1000 - returns
0โ the significant digit is1
The return value comes from this algorithm: the individual significant digit of a single error is โ take the exponent of the first non-zero digit in the error. The digit after this first non-zero digit is the significant one.
Then the method returns the minimum of the individual significant digits of all errors.
So like:
5 +/- 0.0132 + 0.5 - 1
Will yield a return value of -3, since the first error has the lowest significant digit. slay.
This same algorithm is also what determines the significant digit for rounding. And it is extremely important that you realize this isn't carved in stone โ the way the significant digit is computed when errors are around is merely a convention. In this case it stems from particle physics ๐ฌ. It might totally be that in your particular scientific community there are other conventions. One example: using the second non-zero digit only if the first is a 1. iykyk.
๐ error
Returns a reference to an array of errors of the object it's called on.
Unlike the raw_error() method, this one takes proper care to copy all objects and references โ to defy action at a distance โจ. The structure of the returned array reference is akin to the one returned by raw_error().
On top of that, this method rounds all errors to the significant digit as determined by significant_digit().
๐ raw_error
Returns the internal representation of the errors of the current object. Heads up though: just like raw_number(), this does not clone the data for safe use without action at a distance. Instead, it directly returns the internal reference to the error structure. ๐
The structure is an array of errors. Each error may either be:
- a string
- a floating point number
- a
"Math::BigFloat"object - an array reference
In the case of an array reference, it's an asymmetric error, and the inner array contains two strings/numbers/"Math::BigFloat"s.
๐จ note that this practically breaks encapsulation, and code relying on it might break with future releases. fr fr.
๐ as_array
Returns the information stored in the object as an array (i.e. a list in this context) which can be passed to the new() method to recreate the object. cute, right?
The first element of the return list is the number itself. If the object uses "Math::BigFloat" for the internal representation, this element will be a copy of the internal object. Otherwise, it'll be the internal representation of the number with full precision.
Following the number come all the errors, either as numbers, "Math::BigFloat" objects, or arrays containing two asymmetric errors. (Either as numbers or objects, as explained above.) And the data returned by this method is copied deeply before being returned โ no shared refs, no drama. ๐ซถ
โญ round_a_number
This is a helper function which can round a number to the specified significant digit (defined as the return value of the "significant_digit" method):
my $rounded = round_a_number(12.01234567, -3);
# $rounded is now 1.2012e01
๐ฅ COMPARISON ๐ฅ
This section lists the methods that implement different comparisons between objects. let's get into it.
๐ numeric_cmp
Implements a numeric comparison of two numbers. It compares the object it's called on to the first argument of the method. If the first argument is omitted or undefined, the method returns "undef".
"Numeric comparison" here means the represented numbers get rounded and then compared. If you want a comparison that takes errors into account, go peek at the full_cmp() method instead.
Return values, bestie:
-1โ the rounded number represented by the object is numerically less than the rounded number represented by the first argument0โ they're equal1โ the object's rounded number is more than that of the argument
This method implements the overloaded numeric comparison operations. โจ
๐ full_cmp
Implements a full comparison of two objects. That means it takes their numeric values, rounds them, and compares them just like the numeric_cmp() method does.
But if the numbers are equal, this method iterates over the errors, rounds them, and then compares them. If all errors are equal, it returns 0. If an error is found to differ, it returns 1 in case the object's error is larger, and -1 in case the argument's error is larger.
Now, comparing an asymmetric error to a symmetric error is a special case. It can never be the same error, hence the method will not return 0. Instead, it guesses which error is larger by using the upper error bound of the asymmetric error. (Well, yes, not very useful. ๐ญ)
๐ SUPPORT ๐
Bugs should be reported via the CPAN bug tracker at
<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Number-WithError>
For other issues, contact the author. ๐ซถ
๐ธ SEE ALSO ๐ธ
You may use Math::BigFloat with this module. Also, it should be possible to use Math::Symbolic to calculate larger formulas. Just assign a "Number::WithError" object to the "Math::Symbolic" variables and it should work. โจ
You also possibly want to have a look at the prefork pragma.
The test suite is implemented using the Test::LectroTest module. In order to keep the total test time in reasonable bounds, the default number of test attempts to falsify the test properties is kept at a low number of 100. You can enable more rigorous testing by setting the environment variable "PERL_TEST_ATTEMPTS" to a higher value. A value in the range of 1500 to 3000 is probably a good idea, but takes a long time to test. ๐ฅ
๐ AUTHOR ๐
Steffen Mueller <smueller@cpan.org>, <http://steffen-mueller.net/>
๐ฆ COPYRIGHT ๐ฆ
Copyright 2006-2010 Steffen Mueller.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
and that's the whole page, bestie!! ๐โจ you just read the manual for Number::WithError(3) โ from perl v5.42.0, dated 2025-07-25. go forth and round your errors with confidence ๐
๐ซถ
๐ฆ where this page comes from
- fedora 43: perl-Number-WithError 1.01-36.fc43 ยท GPL-1.0-or-later OR Artistic-1.0-Perl
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms