NAME

Locale::Unicode::RBNF::Util - Numeric helpers for Locale::Unicode::RBNF

SYNOPSIS

use Locale::Unicode::RBNF::Util qw( :all );
my $n = to_i64( pow_u64( 10, 19 ) );
my $q = idiv( -7, 2 );
# -3

VERSION

v0.1.0

DESCRIPTION

Internal module. It reproduces the int64_t, uint64_t and double behaviour that ICU4C's rule-based number format relies upon, so that results are identical to ICU, including its overflow behaviour.

EXPORTS

Nothing is exported by default. All the functions below can be imported individually, or all at once with the tag :all.

VARIABLES

  • $MAX_MANTISSA

    2^54 - 1, the value of ICU uprv_maxMantissa().

  • $INT64_MAX and $INT64_MIN

    The limits of an int64_t.

  • $UINT64_MOD

    2^64, as a Math::BigInt object.

FUNCTIONS

dbl_to_i32

my $i = dbl_to_i32( $double );

This is static_cast<int32_t> of a double. Out of range, this is undefined behaviour in C++: x86 yields INT32_MIN, while aarch64 saturates, as does the (int) cast of Java in ICU4J. The defined Java semantics are used: the value is truncated towards zero, saturated to the int32_t range, and NaN yields 0.

dec_from_number

my $dec = dec_from_number( $number, $is_int );

Returns the decimal representation of a number as an hash reference with the keys neg, digits and scale, where the value is digits times 10 to the power of scale, and digits neither starts nor ends with a zero. Zero has empty digits.

If $is_int is true, the number is taken digit for digit, so that integers beyond 2^53 keep their precision. Otherwise, the shortest representation of the double that round-trips is used, which is what ICU DecimalQuantity::setToDouble() produces.

dec_get_digit

my $digit = dec_get_digit( $dec, $magnitude );

This is ICU DecimalQuantity::getDigit(): it returns the digit at the given power of ten, or 0 outside the digits stored.

dec_is_zero

my $bool = dec_is_zero( $dec );

Returns true if the decimal representation is zero.

dec_lower_display_magnitude

my $magnitude = dec_lower_display_magnitude( $dec );

This is ICU DecimalQuantity::getLowerDisplayMagnitude() for a quantity with no minimum fraction digits: the power of ten of the last fraction digit, or 0 if there is none.

dec_round

my $ok = dec_round( $dec, $magnitude, $mode );

This is ICU DecimalQuantity::roundToMagnitude(): it rounds the decimal representation, in place, to the given power of ten, with one of the rounding modes ceiling, floor, down, up, half_even (the default), half_down, half_up, half_odd, half_ceiling, half_floor and unnecessary.

It returns false when the mode is unnecessary and rounding would have changed the value, in which case the value is left unchanged, and ICU sets U_FORMAT_INEXACT_ERROR. It returns true otherwise.

dec_to_number

my $number = dec_to_number( $dec );

Returns the decimal representation as a Perl number.

from_double

my $int = from_double( $double );

This is ICU util64_fromDouble(): the double is clamped to plus or minus uprv_maxMantissa(), 2^54 - 1, then truncated towards zero. NaN yields 0.

idiv

my $q = idiv( $x, $y );

Returns the integer division of $x by $y with C semantics, that is truncated towards zero.

imod

my $r = imod( $x, $y );

Returns the remainder of the integer division of $x by $y with C semantics, that is with the sign of $x.

is_infinite

my $bool = is_infinite( $number );

Returns true if the number is defined and is a positive or negative infinity.

is_nan

my $bool = is_nan( $number );

Returns true if the number is defined and is NaN.

is_pattern_ws

my $bool = is_pattern_ws( $char );

This is ICU PatternProps::isWhiteSpace(): it returns true if the character belongs to the Pattern_White_Space set. That set is immutable by Unicode policy, so it is spelled out in the code.

lcm

my $lcm = lcm( $x, $y );

This is util_lcm() of ICU nfrs.cpp: the least common multiple, computed with the binary gcd of Knuth, then x / gcd * y, all in int64_t arithmetic. It returns 0 if the gcd is 0.

pow_u64

my $n = pow_u64( $base, $exponent );

This is ICU util64_pow(): it raises the base to the power of the exponent in uint64_t arithmetic, so that the result wraps modulo 2^64 as the C++ code does. Beyond 2^53, the exact wrapped value is computed with Math::BigInt. The result is unsigned; use "to_i64" where ICU stores it in an int64_t.

str_insert

str_insert( \$string, $pos, $text );

This is ICU UnicodeString::insert(): it inserts the text into the string referenced, at the position given, pinned within the string.

to_i32

my $i = to_i32( $integer );

This is static_cast<int32_t> of an integral value: two's complement truncation.

to_i64

my $i = to_i64( $unsigned );

Converts a uint64_t value to an int64_t (two's complement), as happens implicitly in ICU.

SEE ALSO

Locale::Unicode::RBNF

AUTHOR

Jacques Deguest <jack@deguest.jp>

COPYRIGHT & LICENSE

Copyright(c) 2026 DEGUEST Pte. Ltd.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.