Number formatting support in Plurimath
Introduction
Number formatting is an essential aspect of presenting numerical data in a way that is consistent with regional conventions and user preferences. There are myriad number formatting conventions and standards that are widely used in various cultures and fields.
Plurimath now supports number formatting, allowing precise control over how numbers are presented, enhancing both readability and precision using the newly implemented number formatting feature.
Number formatting
Traditional conventions
Different cultures, orthographies and organizations have different conventions for formatting numbers.
These include practices on how to represent decimal points, digit grouping, digit grouping separators, and various mathematical notations.
 Decimal point symbol

In the United States, a full stop (
.
) is used as the decimal point separator, while in many European countries, a comma (,
) is used instead.  Digit grouping delimiter

In the United States, numbers are often grouped in sets of three digits using commas, such as 1,234,567.89. In some European countries, numbers are grouped using periods, such as 1.234.567,89, or a thin space, such as 1 234 567,89.
 Digit grouping practices

In Western cultures, numbers ahead of the decimal are often grouped threes. Numbers behind the decimal are less standardized, but are often grouped in sets of two or three.
 Mathematical notation

In scientific and engineering contexts, numbers are often formatted using scientific notation, which expresses numbers as a coefficient multiplied by a power of 10. For example, the number 123,456,789 can be expressed in scientific notation as 1.23456789 x 10^8.
Standardized conventions
Standardization organizations have established standards for number formatting to ensure uniformity and accuracy.
The SI system (International System of Units), by the BIPM (Bureau International des Poids et Mesures), specifies rules regarding the decimal point symbol, digit grouping delimiter and digit groupings.
ISO 800002, the international standard for quantities and units, used by all ISO and IEC standards, also provides guidelines for number formatting in a different manner than the SI system.
Plurimath number formatting
To address these needs, Plurimath now allows precise control over how numbers are presented through its number formatting feature.
Plurimath’s number formatter allows users to format numbers based on locale, ensuring that the formatting adheres to regional conventions and enhances both readability and precision.
Using the number formatter
General
The number formatting feature is implemented in the Plurimath::NumberFormatter
class, which allows users to reuse a single formatter class for formatting
multiple numbers.
A simple twostep process to format numbers:

Create a new
Plurimath::NumberFormatter
object, passing the desired locale and overriding options as arguments. 
Call the
localized_number
method on the formatter object, passing the number to be formatted as a string and any additional options.
The final formatted number is formatted according to the following configuration priority, ordered from highest to lowest precedence:

The
format
hash given toPlurimath::NumberFormatter#localized_number

The
localize_number
string in the creation of aPlurimath::NumberFormatter

The
localizer_symbols
hash in the creation of aPlurimath::NumberFormatter

The default configuration of the locale of the
Plurimath::NumberFormatter
Creating a number formatter
The NumberFormatter
is used to format numbers based on the locale and the
formatting configuration provided.
Syntax:
Plurimath::NumberFormatter
objectformatter = Plurimath::NumberFormatter.new(
<localesymbol>, # mandatory (1)
localize_number: <localizestring>, # optional (2)
localizer_symbols: <formathash> # optional (3)
)

The locale to be used for number formatting.

String with a specific sequence of characters to define the number formatting. Use only one of
localize_number
orlocalizer_symbols
. 
Hash containing relevant options for number formatting, as the format options hash. Use only one of
localize_number
orlocalizer_symbols
.
Where,
<localesymbol>

(mandatory) The locale to be used for number formatting. Accepted values are listed in the
Plurimath::Formatter::SupportedLocales::LOCALES
constant. localize_number: <localizestring>

(optional) A string containing a specific sequence of characters that defines the number formatting. Use either
localize_number
orlocalizer_symbols
to set the number formatting pattern.See
localize_number
for details. localizer_symbols: <formathash>

(optional) A hash containing the relevant options for number formatting. Use either
localize_number
orlocalizer_symbols
to set the number formatting pattern.See format options hash for details.
Plurimath::NumberFormatter
object using the :en
localeformatter = Plurimath::NumberFormatter.new(:en)
# => #<Plurimath::NumberFormatter:0x00007f8b1b8b3b10 @locale=:en>
Configuring the number formatter
The Plurimath::NumberFormatter
object can be configured using either the
localize_number
or localizer_symbols
options.
Via "format options" using localizer_symbols
The localizer_symbols
key is used to set the number formatting pattern
through a Hash object containing specified options.
This Hash object is called the "format options Hash".
Available options are explained below.
Note

Each option takes an input of a certain specified type (String or
Numeric ). Using an input type other than the specified type will result in
errors or incorrect output.

The values passed to localizer_symbols
persist as long as the initialized
NumberFormatter
instance is accessible. It is therefore useful in scenarios
when configuration will be static or changes are not required very often.
decimal

(
String
value) Symbol to use for the decimal point. Accepts a character.Example 2. Using the ',' "comma" symbol as the decimal point"32232.232" ⇒ "32232,232"
Example 3. Using the '.' "full stop" symbol as the decimal point"32232.232" ⇒ "32232.232"
digit_count

(
Numeric
value) Total number of digits to render, with the value truncated. Accepts an integer value.Example 4. Specifying a total of 6 digits in rendering the number"32232.232" ⇒ "32232.2"
group

(
String
value) Delimiter to use between groups of digits specified ingroup_digits
. Accepts a character. (default is not to group digits.)Example 5. Using the unicode thin space (THIN SPACE, U+2009) as the grouping delimiter"32232.232" ⇒ "32 232.232"
group_digits

(
Numeric
value) Number of digits to group the integer portion, grouping from right to left. Accepts an integer value. (default is 3 in most locales.)Example 6. Using the unicode thin space as the grouping delimiter, and grouping every 2 digits"32232.232" ⇒ "3 22 32.232"
fraction_group

(
String
value) Delimiter to use between groups of fractional digits specified infraction_group_digits
. Accepts a character.Example 7. Using the unicode thin space as the fraction grouping delimiter"32232.232131" ⇒ "32232.232 131".
fraction_group_digits

(
Numeric
value) Number of digits in each group of fractional digits, grouping from left to right. Accepts an integer value.Example 8. Using the unicode thin space as the fraction grouping delimiter, and grouping every 2 fraction digits"32232.232131" ⇒ "32232.23 21 31"
significant

(
Numeric
value) Sets the number of significant digits to show, with the value rounded. notation

(
String
value) Specifies the mathematical notation to be used. Accepts the following values.e

Use exponent notation.
Example 9. Example of using exponent notation1.23456789e8
scientific

Use scientific notation.
Example 10. Example of using scientific notation1.23456789 × 10⁸
engineering

Use engineering notation, where the exponent of ten is always selected to be divisible by three to match the common metric prefixes.
Example 11. Example of using engineering notation123.456789 × 10⁶
e

(
String
value) Symbol to use for exponents in E notation (default valueE
). (used in the mode:e
only).Example 12. Using the lowercase 'e' symbol as the exponent symbol3.2232232e5
times

(
String
value) Symbol to use for multiplication where required by the notation (used in the modes:scientific
andengineering
). Defaults to×
.Example 13. Using the '·' "middle dot" symbol as the multiplication symbol32.232232 · 104
exponent_sign

(
String
value) Whether to use a plus sign to indicate positive exponents, in exponentbased notation (used in the modes:e
,scientific
,engineering
). Legal values are:plus

The
+
symbol is used.Example 14. Using the plus sign to indicate positive exponents32.232232 × 10⁺⁴
These options are to be grouped under a single Hash object.
localizer_symbols
{
decimal: ",", # replaces the decimal point with the passed string
group_digits: 2, # groups integer part into passed integer
group: "'", # places the string between grouped parts of the integer
fraction_group_digits: 3, # groups fraction part into passed integer
fraction_group: ",", # places the string between grouped parts of the fraction
}
Via the localize_number
option
The localize_number
option accepts a formatting pattern specified as a string,
using the hash symbol #
to represent a digit placeholder.
The localize_number
option is useful when you want to format numbers in a
specific way that is not covered by the localizer_symbols
option.
A sample value of #,##0.### ###
is interpreted as the following
configuration in the format options hash:
group

This parameter is set to the very first nonhash character before 0. If there is no nonhash character before
#
+0
, then the default group delimiter will be nil.In this example, it is
,
. group_digits

This parameter is set to the "count of all hashes + 1" (including the zero). Minimum 1 hash symbol is required.
In this example,
##0
sets the value to 3. decimal

This parameter is set to the character immediately to the right of
0
. This is mandatory.In this example, it is
.
. fraction_group_digits

This parameter is set to "count of all the hashes right next to decimal". Minimum 1 hash symbol is required.
In our example, '###' sets the value to 3.
fraction_group

This parameter is set to the first character after
fraction_group_digits
. If there is no nonhash character afterfraction_group_digits
, it is set to nil.In this example it is
' '
(a space).
localize_number
optionformatter = Plurimath::NumberFormatter.new(:en, localize_number: "#,##0.### ###")
formatter.localized_number("1234.56789")
# => "1,234.568 9"
Formatting a number using NumberFormatter
The localized_number
method is used to format a number given a
NumberFormatter
instance.
Syntax:
localized_number
formatter.localized_number(
<number>, # mandatory (1)
locale: <localesymbol>, # optional (2)
precision: <precisionnumber>, # optional (3)
format: <formathash> # optional (4)
)

number
: (mandatory) The number to be formatted. Value should be a Numeric, i.e. Integer, Float, or BigDecimal. 
localesymbol
: (optional) The locale to be used for number formatting. Value is a symbol. Overrides the locale set during the creation of theNumberFormatter
object. If not provided, the locale of theNumberFormatter
instance will be used. 
precisionnumber
: (optional) The number of decimal places to round the number to. If not provided, the precision will be set to the input’s decimal digits count. 
formathash
: (optional) A Hash containing the relevant options for number formatting, that overrides thelocalizer_symbols
configuration of theNumberFormatter
. Takes a Hash in the form of the format options hash.precision: <precisionnumber>

Number of fractional digits to render. Accepts an integer value.
Example 16. Specifying a precision of 6 digits"32232.232" ⇒ "32232.232000"
localized_number
method for the English localeformatter = Plurimath::NumberFormatter.new(:en)
formatter.localized_number("1234.56789")
# => "1,234.56789"
localized_number
method for the French localeformatter = Plurimath::NumberFormatter.new(:fr)
formatter.localized_number("1234.56789")
# => "1 234,56789"
The locale and precision set in the NumberFormatter
can be overridden by
passing the locale
and precision
options to the localized_number
method.
localized_number
formatter = Plurimath::NumberFormatter.new(:en)
formatter.localized_number("1234.56789", locale: :de, precision: 6)
# => "1.234,567890"
Overriding specified NumberFormatter
options using the format
key
The format
option is used to override the specified configuration of the
NumberFormatter
object.
It expects a Hash in the form of the format options hash.
formatter = Plurimath::NumberFormatter.new(:en)
formatter.localized_number(
"1234.56789",
format: {
decimal: "x",
# other supported options
}
)
# => "1,234x56789"
format
key in the localized_number
methodformatter = Plurimath::NumberFormatter.new(:en)
formatter.localized_number(
"1234.56789",
format: {
decimal: "x",
group_digits: 2,
group: "'",
fraction_group_digits: 3,
fraction_group: ","
}
)
# => "12'34x567,89"
Supported locales
Plurimath supports the following locales for number formatting. The locale values are sourced from the Unicode CLDR repository.
The list of locales and their values are given in the file
lib/plurimath/formatter/supported_locales.rb
.
The locales and their values can be obtained through the following code.
Plurimath::Formatter::SupportedLocales::LOCALES[:en]
# => { decimal: ".", group: "," }
Locale  Decimal delimiter  Group delimiter 

































































































































































































































































































Conclusion
Plurimath’s number formatting feature provides precise control over how numbers are presented, adhering to regional conventions and enhancing both readability and precision.
Planning into the future: this feature will soon find its way into the math representation languages supported in Plurimath, such that formulas generated will comply with the specified number formatting practices.
For bug reports and feature requests, please report them at the Plurimath Issues page on GitHub.
Making math look good, one feature at a time!