Data-Float

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN


  - in Build.PL, explicitly declare configure-time requirements

  - remove bogus "exit 0" from Build.PL

  - add MYMETA.yml to .cvsignore

v0.009 2008-04-06

  - refer to optional constants more carefully in the code, to avoid
    syntax problems on systems that lack infinities and NaNs

  - fix a skip count that caused false test failures on systems lacking
    signed zeroes

v0.008 2008-04-02

  - bugfix: in initialisation, correctly override any ambient
    $SIG{__DIE__}

v0.007 2007-10-02

Changes  view on Meta::CPAN

  - float_hex(): new option "hex_prefix_string" to control the "0x" prefix

  - test classification functions, examination functions, string
    conversion functions, and manipulation functions (all the functions
    that were not being tested)

  - test all functions for lack of side effects on zero arguments and
    purity of zero results

  - in documentation, note new standard-conforming behaviour of copysign()
    with a NaN second argument

  - in documentation, note that hex_float() accepts the special "0.0"
    form of input without a sign, as well as with one

  - in documentation, where the IEEE standard nature of functions is
    noted, add discussion of non-conforming behaviour on NaNs

  - in documentation, change some variable names in the synopsis for
    clarity

  - test POD syntax and coverage, and rename some internal functions to
    satisfy the coverage test

  - tweak tests on constants to avoid infinite loops if importing constant
    functions fails

  - build with Module::Build instead of ExtUtils::MakeMaker

  - complete dependency list

  - include signature in distribution

  - in documentation, separate "license" section from "copyright" section

v0.005 2007-01-25

  - bugfix: change behaviour of copysign() with a NaN as the second
    argument to that specified by IEEE 754: it is not an error but
    (in the context of Perl's opaque NaNs) results in copying an
    unpredictable sign

  - add hex_float() function to input floating point values in hexadecimal

  - add IEEE 754 function signbit()

  - float_id_cmp(): tighten specification of return values to match
    Perl's <=> operator (actual behaviour always matched the tighter spec,
    it just wasn't documented and tested)

Changes  view on Meta::CPAN

  - in documentation, note that both arguments to nextafter() must be
    floating point values

  - in documentation, note standard nature of signbit(), copysign(),
    and nextafter()

  - in documentation, note float_id_cmp()'s relation to the IEEE 754r
    function totalorder()

  - in documentation, note that Perl does not distinguish between
    different NaNs

  - in documentation, give a second definition of max_integer (equivalent
    to the first)

  - add test for consistency of constants

  - in documentation, reference Scalar::Number

  - remove now-useless test t/use.t

Changes  view on Meta::CPAN

  - in documentation, note the slightly misleading nature of the names
    "significand_bits" and "max_integer"

  - reference Data::Integer and perlnumber(1) in documentation

v0.003 2006-08-08

  - float_hex(): add OPTIONS parameter to control details of output
    formatting

  - when looking for NaNs, see whether the string "nan" qualifies

  - slight clarification to documentation of significand_step

v0.002 2006-08-03

  - bugfix: in mult_pow2(), copysign(), and nextafter(), take care
    to return a pristine signed zero when returning zero: they were
    returning zeroes that got broken (due to the Perl bug noted in the
    documentation) by internal arithmetic

lib/Data/Float.pm  view on Meta::CPAN


Some floating point formats include special infinite values.  These are
generated by overflow, and by some arithmetic cases that mathematically
generate infinities.  There are two infinite values: positive infinity
and negative infinity.

Perl does not always generate infinite values when normal floating point
behaviour calls for it.  For example, the division C<1.0/0.0> causes an
exception rather than returning an infinity.

=item not-a-number (NaN)

This type of value exists in some floating point formats to indicate
error conditions.  Mathematically undefined operations may generate NaNs,
and NaNs propagate through all arithmetic operations.  A NaN has the
distinctive property of comparing numerically unequal to all floating
point values, including itself.

Perl does not always generate NaNs when normal floating point behaviour
calls for it.  For example, the division C<0.0/0.0> causes an exception
rather than returning a NaN.

Perl has only (at most) one NaN value, even if the underlying system
supports different NaNs.  (IEEE 754 arithmetic has NaNs which carry a
quiet/signal bit, a sign bit (yes, a sign on a not-number), and many
bits of implementation-defined data.)

=back

=head2 Mixing floating point and integer values

Perl does not draw a strong type distinction between native integer
(see L<Data::Integer>) and native floating point values.  Both types
of value can be stored in the numeric part of a plain (string) scalar.

lib/Data/Float.pm  view on Meta::CPAN

=item have_subnormal

Truth value indicating whether there are subnormal floating point values.

=item have_infinite

Truth value indicating whether there are infinite floating point values.

=item have_nan

Truth value indicating whether there are NaN floating point values.

It is difficult to reliably generate a NaN in Perl, so in some unlikely
circumstances it is possible that there might be NaNs that this module
failed to detect.  In that case this constant would be false but a NaN
might still turn up somewhere.  What this constant reliably indicates
is the availability of the C<nan> constant below.

=back

=head2 Extrema

=over

=item significand_bits

lib/Data/Float.pm  view on Meta::CPAN

The positive infinite value.  (Exists only if there are infinite values,
as indicated by the C<have_infinite> constant.)

=item neg_infinity

The negative infinite value.  (Exists only if there are infinite values,
as indicated by the C<have_infinite> constant.)

=item nan

Not-a-number.  (Exists only if NaN values were detected, as indicated
by the C<have_nan> constant.)

=back

=cut

sub _mk_constant($$) {
	my($name, $value) = @_;
	no strict "refs";
	*{__PACKAGE__."::".$name} = sub () { $value };

lib/Data/Float.pm  view on Meta::CPAN


Returns true iff VALUE is a subnormal floating point value.

=cut

sub float_is_subnormal($) { float_class($_[0]) eq "SUBNORMAL" }

=item float_is_nzfinite(VALUE)

Returns true iff VALUE is a non-zero finite value (either normal or
subnormal; not zero, infinite, or NaN).

=cut

sub float_is_infinite($);

sub float_is_nzfinite($) {
	my($val) = @_;
	return $val != 0.0 && $val == $val && !float_is_infinite($val);
}

lib/Data/Float.pm  view on Meta::CPAN

=cut

sub float_is_zero($) {
	my($val) = @_;
	return $val == 0.0;
}

=item float_is_finite(VALUE)

Returns true iff VALUE is a finite value (either normal, subnormal,
or zero; not infinite or NaN).

=cut

sub float_is_finite($) {
	my($val) = @_;
	return $val == $val && !float_is_infinite($val);
}

=item float_is_infinite(VALUE)

lib/Data/Float.pm  view on Meta::CPAN

=cut

sub float_is_infinite($) {
	return undef unless have_infinite;
	my($val) = @_;
	return $val == $pos_infinity || $val == $neg_infinity;
}

=item float_is_nan(VALUE)

Returns true iff VALUE is a NaN.

=cut

sub float_is_nan($) {
	my($val) = @_;
	return $val != $val;
}

=back

=head2 Examination

=over

=item float_sign(VALUE)

Returns "B<+>" or "B<->" to indicate the sign of VALUE.  An unsigned
zero returns the sign "B<+>".  C<die>s if VALUE is a NaN.

=cut

sub signbit($);

sub float_sign($) {
	my($val) = @_;
	croak "can't get sign of a NaN" if $val != $val;
	return signbit($val) ? "-" : "+";
}

=item signbit(VALUE)

VALUE must be a floating point value.  Returns the sign bit of VALUE:
0 if VALUE is positive or a positive or unsigned zero, or 1 if VALUE is
negative or a negative zero.  Returns an unpredictable value if VALUE
is a NaN.

This is an IEEE 754 standard function.  According to the standard NaNs
have a well-behaved sign bit, but Perl can't see that bit.

=cut

sub signbit($) {
	my($val) = @_;
	return (have_signed_zero && $val == 0.0 ?
		sprintf("%+.f", $val) eq "-0" : $val < 0.0) ? 1 : 0;
}

lib/Data/Float.pm  view on Meta::CPAN


The string that is prefixed to hexadecimal digits.  Default "B<0x>".
Make it the empty string to suppress the prefix.

=item B<infinite_string>

The string that is returned for an infinite magnitude.  Default "B<inf>".

=item B<nan_string>

The string that is returned for a NaN value.  Default "B<nan>".

=item B<neg_sign>

The string that is prepended to a negative value (including negative
zero).  Default "B<->".

=item B<pos_sign>

The string that is prepended to a positive value (including positive or
unsigned zero).  Default "B<+>".  Make it the empty string to suppress

lib/Data/Float.pm  view on Meta::CPAN


If the value given in the string cannot be exactly represented in the
floating point type because it has too many fraction bits, the nearest
representable value is returned, with ties broken in favour of the value
with a zero low-order bit.  If the value given is too large to exactly
represent then an infinity is returned, or the largest finite value if
there are no infinities.

Additional input formats are accepted for special values.
"[I<s>]B<inf>[B<inity>]" returns an infinity, or C<die>s if there are
no infinities.  "[I<s>][B<s>]B<nan>" returns a NaN, or C<die>s if there
are no NaNs available.

All input formats are understood case insensitively.  The function
correctly interprets all possible outputs from C<float_hex> with default
settings.

=cut

sub hex_float($) {
	my($str) = @_;
	if($str =~ /\A([-+]?)(?:0x)?([0-9a-f]+)(?:\.([0-9a-f]+)+)?

lib/Data/Float.pm  view on Meta::CPAN


=item float_id_cmp(A, B)

This is a comparison function supplying a total ordering of floating
point values.  A and B must both be floating point values.  Returns -1,
0, or +1, indicating whether A is to be sorted before, the same as,
or after B.

The ordering is of the identities of floating point values, not their
numerical values.  If zeroes are signed, then the two types are considered
to be distinct.  NaNs compare equal to each other, but different from
all numeric values.  The exact ordering provided is mostly numerical
order: NaNs come first, followed by negative infinity, then negative
finite values, then negative zero, then positive (or unsigned) zero,
then positive finite values, then positive infinity.

In addition to sorting, this function can be useful to check for a zero
of a particular sign.

=cut

sub float_id_cmp($$) {
	my($a, $b) = @_;

lib/Data/Float.pm  view on Meta::CPAN

		return $a <=> $b;
	}
}

=item totalorder(A, B)

This is a comparison function supplying a total ordering of floating point
values.  A and B must both be floating point values.  Returns a truth value
indicating whether A is to be sorted before-or-the-same-as B.  That is,
it is a <= predicate on the total ordering.  The ordering is the same as
that provided by C<float_id_cmp>: NaNs come first, followed by negative
infinity, then negative finite values, then negative zero, then positive
(or unsigned) zero, then positive finite values, then positive infinity.

This is an IEEE 754r standard function.  According to the standard it
is meant to distinguish different kinds of NaNs, based on their sign
bit, quietness, and payload, but this function (like the rest of Perl)
perceives only one NaN.

=cut

sub totalorder($$) { float_id_cmp($_[0], $_[1]) <= 0 }

=back

=head2 Manipulation

=over

lib/Data/Float.pm  view on Meta::CPAN

VALUE by two to the power EXP.  This gives exact results, except in
cases of underflow and overflow.  The range of EXP is not constrained.
All normal floating point multiplication behaviour applies.

=item copysign(VALUE, SIGN_FROM)

VALUE and SIGN_FROM must both be floating point values.  Returns a
floating point value with the magnitude of VALUE and the sign of
SIGN_FROM.  If SIGN_FROM is an unsigned zero then it is treated as
positive.  If VALUE is an unsigned zero then it is returned unchanged.
If VALUE is a NaN then it is returned unchanged.  If SIGN_FROM is a NaN
then the sign copied to VALUE is unpredictable.

This is an IEEE 754 standard function.  According to the standard NaNs
have a well-behaved sign bit, which can be read and modified by this
function, but Perl only perceives one NaN and can't see its sign bit,
so behaviour on NaNs is not standard-conforming.

=cut

sub copysign($$) {
	my($val, $signfrom) = @_;
	return $val if float_is_nan($val);
	$val = -$val if signbit($val) != signbit($signfrom);
	return $val;
}

=item nextup(VALUE)

VALUE must be a floating point value.  Returns the next representable
floating point value adjacent to VALUE with a numerical value that is
strictly greater than VALUE, or returns VALUE unchanged if there is
no such value.  Infinite values are regarded as being adjacent to the
largest representable finite values.  Zero counts as one value, even if
it is signed, and it is adjacent to the smallest representable positive
and negative finite values.  If a zero is returned, because VALUE is
the smallest representable negative value, and zeroes are signed, it is
a negative zero that is returned.  Returns NaN if VALUE is a NaN.

This is an IEEE 754r standard function.

=cut

sub nextup($) {
	my($val) = @_;
	return $val if $val != $val || $val == max_number;
	return -(max_finite) if have_infinite && $val == -(max_number);
	return min_finite if $val == 0.0;

lib/Data/Float.pm  view on Meta::CPAN

=item nextdown(VALUE)

VALUE must be a floating point value.  Returns the next representable
floating point value adjacent to VALUE with a numerical value that
is strictly less than VALUE, or returns VALUE unchanged if there is
no such value.  Infinite values are regarded as being adjacent to the
largest representable finite values.  Zero counts as one value, even if
it is signed, and it is adjacent to the smallest representable positive
and negative finite values.  If a zero is returned, because VALUE is
the smallest representable positive value, and zeroes are signed, it is
a positive zero that is returned.  Returns NaN if VALUE is a NaN.

This is an IEEE 754r standard function.

=cut

sub nextdown($) { -nextup(-(my $n = $_[0])) }

=item nextafter(VALUE, DIRECTION)

VALUE and DIRECTION must both be floating point values.  Returns the
next representable floating point value adjacent to VALUE in the
direction of DIRECTION, or returns DIRECTION if it is numerically
equal to VALUE.  Infinite values are regarded as being adjacent to
the largest representable finite values.  Zero counts as one value,
even if it is signed, and it is adjacent to the positive and negative
smallest representable finite values.  If a zero is returned and zeroes
are signed then it has the same sign as VALUE.  Returns NaN if either
argument is a NaN.

This is an IEEE 754 standard function.

=cut

sub nextafter($$) {
	my($val, $dir) = @_;
	return $_[1] if $dir != $dir || $val == $dir;
	return $dir > $val ? nextup($_[0]) : nextdown($_[0]);
}

lib/Data/Float.pm  view on Meta::CPAN

return a pristine one.

As of Perl 5.8.7 stringification of a floating point zero does not
preserve its signedness.  The number-to-string-to-number round trip
turns a positive floating point zero into an integer zero, but accurately
maintains negative and integer zeroes.  If a negative zero gets partially
transformed into an integer zero, as described above, the stringification
that it gets is based on its state at the first occasion on which the
scalar was stringified.

NaN handling is generally not well defined in Perl.  Arithmetic with
a mathematically undefined result may either C<die> or generate a NaN.
Avoid relying on any particular behaviour for such operations, even if
your hardware's behaviour is known.

As of Perl 5.8.7 the B<%> operator truncates its arguments to integers, if
the divisor is within the range of the native integer type.  It therefore
operates correctly on non-integer values only when the divisor is
very large.

=head1 SEE ALSO

t/const.t  view on Meta::CPAN

	ok &{"Data::Float::pos_infinity"} > max_finite;
	ok &{"Data::Float::neg_infinity"} < -max_finite();
	ok max_number == &{"Data::Float::pos_infinity"};
	ok max_number > max_finite;
} else {
	SKIP: { skip "no infinities", 3; }
	ok max_number == max_finite;
}

SKIP: {
	skip "no NaNs", 1 unless have_nan;
	no strict "refs";
	my $nan = &{"Data::Float::nan"};
	ok $nan != $nan;
}

1;

t/copysign.t  view on Meta::CPAN

	ok copysign($ninf, +5) == $pinf;
	ok copysign($pinf, -5) == $ninf;
	ok copysign($ninf, -5) == $ninf;
	ok copysign(+1.2, $pinf) == +1.2;
	ok copysign(-1.2, $pinf) == +1.2;
	ok copysign(+1.2, $ninf) == -1.2;
	ok copysign(-1.2, $ninf) == -1.2;
}

SKIP: {
	skip "NaN not available", 3 unless have_nan;
	no strict "refs";
	my $nan = &{"Data::Float::nan"};
	ok float_is_nan(copysign($nan, +5));
	ok float_is_nan(copysign($nan, $nan));
	ok abs(copysign(+1.2, $nan)) == 1.2;
}

1;

t/hex.t  view on Meta::CPAN

	ok hex_float("iNfiniTy") == $pinf;
	ok hex_float("+infinity") == $pinf;
	ok hex_float("+Infinity") == $pinf;
	ok hex_float("+iNfiniTy") == $pinf;
	ok hex_float("-infinity") == $ninf;
	ok hex_float("-Infinity") == $ninf;
	ok hex_float("-iNfiniTy") == $ninf;
}

SKIP: {
	skip "no NaN", 20 unless have_nan;
	no strict "refs";
	is float_hex(&{"Data::Float::nan"}), "nan";
	is float_hex(&{"Data::Float::nan"}, \%str_opt), "(NAN)";
	ok float_is_nan(hex_float("nan"));
	ok float_is_nan(hex_float("Nan"));
	ok float_is_nan(hex_float("nAn"));
	ok float_is_nan(hex_float("+nan"));
	ok float_is_nan(hex_float("+Nan"));
	ok float_is_nan(hex_float("+nAn"));
	ok float_is_nan(hex_float("-nan"));

t/nextafter.t  view on Meta::CPAN

	ok nextafter(+max_finite(), $pinf) == $pinf;
	ok nextdown( -max_finite())        == $ninf;
	ok nextafter(-max_finite(), $ninf) == $ninf;
	ok nextup(   $ninf)        == -max_finite();
	ok nextafter($ninf, $pinf) == -max_finite();
	ok nextdown( $pinf)        == +max_finite();
	ok nextafter($pinf, $ninf) == +max_finite();
}

SKIP: {
	skip "NaN not available", 5 unless have_nan;
	no strict "refs";
	my $nan = &{"Data::Float::nan"};
	ok float_is_nan(nextup($nan));
	ok float_is_nan(nextdown($nan));
	ok float_is_nan(nextafter($nan, +9));
	ok float_is_nan(nextafter(+1.2, $nan));
	ok float_is_nan(nextafter($nan, $nan));
}

1;



( run in 0.726 second using v1.01-cache-2.11-cpan-4d50c553e7e )