plurimath 0.8.20 → 0.8.21

Sign up to get free protection for your applications and to get access to all the features.
data/README.adoc CHANGED
@@ -12,15 +12,15 @@ remains consistent and accurate regardless of the format it is presented in.
12
12
 
13
13
  Supported math representational languages:
14
14
 
15
- * MathML
16
- * AsciiMath
17
- * UnicodeMath
15
+ * https://www.w3.org/TR/MathML3/[MathML 3] (and https://www.w3.org/TR/mathml4/[MathML 4])
16
+ * https://www.asciimath.org[AsciiMath]
17
+ * http://unicodemath.org[UnicodeMath] (https://www.unicode.org/notes/tn28/UTN28-PlainTextMath-v3.2.pdf[UnicodeMath v3.2])
18
18
  * LaTeX math
19
- * OMML
19
+ * Microsoft Office Math Markup Language (OMML) https://devblogs.microsoft.com/math-in-office/officemath/["OfficeMath"]
20
20
 
21
21
  Supported units representation languages:
22
22
 
23
- * UnitsML
23
+ * https://www.unitsml.org[UnitsML]
24
24
 
25
25
 
26
26
  == Benefits
@@ -68,7 +68,7 @@ $ gem install plurimath
68
68
  Plurimath provides a Command Line Interface (CLI) tool for converting between
69
69
  different math formats.
70
70
 
71
- NOTE: Before continuing please ensure you have the gem installed.
71
+ NOTE: Before continuing, please ensure you have the gem installed.
72
72
 
73
73
  To convert math equations between formats, use the following command followed by
74
74
  appropriate options.
@@ -106,26 +106,33 @@ Splits MathML and OMML output into multiple equations. Boolean option (`true`,
106
106
  `false`).
107
107
 
108
108
 
109
- === Convert an AsciiMath equation to MathML
110
-
109
+ [example]
110
+ .Convert an AsciiMath equation to MathML
111
+ ====
111
112
  [source,bash]
112
113
  ----
113
114
  plurimath convert -i "sqrt(x^2 + y^2)" -f asciimath -t mathml
114
115
  ----
116
+ ====
115
117
 
116
- === Convert an OMML equation to MathML with DisplayStyle
117
-
118
+ [example]
119
+ .Convert an OMML equation to MathML with DisplayStyle
120
+ ====
118
121
  [source,bash]
119
122
  ----
120
123
  plurimath convert -i "equation" -f omml -t mathml -d true
121
124
  ----
125
+ ====
122
126
 
123
- === Convert equations from a file and output as UnicodeMath
124
-
127
+ [example]
128
+ .Convert equations from a file and output as UnicodeMath
129
+ ====
125
130
  [source,bash]
126
131
  ----
127
132
  plurimath convert -e <file_path> -t unicodemath
128
133
  ----
134
+ ====
135
+
129
136
 
130
137
  For more detailed information and additional options, use:
131
138
 
@@ -219,6 +226,7 @@ Once you have a `Plurimath::Math::Formula` object, you can convert it to
219
226
  AsciiMath, MathML, LaTeX, UnicodeMath, or OMML by calling the respective
220
227
  conversion function on the `Formula` object.
221
228
 
229
+
222
230
  ==== AsciiMath output conversion
223
231
 
224
232
  [source,ruby]
@@ -306,6 +314,983 @@ omml = formula.to_omml
306
314
  ----
307
315
 
308
316
 
317
+ == Number formatting
318
+
319
+ === Introduction
320
+
321
+ Number formatting is an essential aspect of presenting numerical data in a way
322
+ that is consistent with regional conventions and user preferences.
323
+ There are myriad number formatting conventions and standards that are
324
+ widely used in various cultures and fields.
325
+
326
+ To address these needs, Plurimath now allows precise control over how
327
+ numbers are presented through its number formatting feature.
328
+
329
+ Plurimath's number formatter allows users to format numbers based on locale,
330
+ ensuring that the formatting adheres to regional conventions and enhances both
331
+ readability and precision.
332
+
333
+ For more details, please refer to the blog post
334
+ link:https://www.plurimath.org/blog/2024-07-09-number-formatter/[**Number formatting support in Plurimath**]
335
+
336
+ === Existing conventions
337
+
338
+ ==== Traditional conventions
339
+
340
+ Different cultures, orthographies and organizations have different conventions
341
+ for formatting numbers.
342
+
343
+ These include practices on how to represent decimal points, digit grouping,
344
+ digit grouping separators, and various mathematical notations.
345
+
346
+ Decimal point symbol::
347
+ In the United States, a full stop (`.`) is used as the decimal point
348
+ separator, while in many European countries, a comma (`,`) is used instead.
349
+
350
+ Digit grouping delimiter::
351
+ In the United States, numbers are often grouped in sets of three digits using
352
+ commas, such as 1,234,567.89. In some European countries, numbers are grouped
353
+ using periods, such as 1.234.567,89, or a thin space, such as 1 234 567,89.
354
+
355
+ Digit grouping practices::
356
+ In Western cultures, numbers ahead of the decimal are often grouped threes.
357
+ Numbers behind the decimal are less standardized, but are often grouped in sets
358
+ of two or three.
359
+
360
+ Mathematical notation::
361
+ In scientific and engineering contexts, numbers are often formatted using
362
+ scientific notation, which expresses numbers as a coefficient multiplied by a
363
+ power of 10. For example, the number 123,456,789 can be expressed in scientific
364
+ notation as 1.23456789 x 10^8.
365
+
366
+
367
+ ==== Standardized conventions
368
+
369
+ Standardization organizations have established standards for number formatting
370
+ to ensure uniformity and accuracy.
371
+
372
+ The https://www.bipm.org/en/measurement-units[SI system (International System of Units)],
373
+ by the https://www.bipm.org[BIPM (Bureau International des Poids et Mesures)],
374
+ specifies rules regarding the decimal point symbol, digit grouping delimiter and
375
+ digit groupings.
376
+
377
+ https://www.iso.org/standard/64973.html[ISO 80000-2], the international standard
378
+ for quantities and units, used by all ISO and IEC standards, also provides
379
+ guidelines for number formatting in a different manner than the SI system.
380
+
381
+
382
+ === Using the number formatter
383
+
384
+ ==== General
385
+
386
+ The number formatting feature is implemented in the `Plurimath::NumberFormatter`
387
+ class, which allows users to re-use a single formatter class for formatting
388
+ multiple numbers.
389
+
390
+ A simple two-step process to format numbers:
391
+
392
+ . Create a new `Plurimath::NumberFormatter` object, passing the desired locale
393
+ and overriding options as arguments.
394
+
395
+ . Call the `localized_number` method on the formatter object, passing the
396
+ number to be formatted as a string and any additional options.
397
+
398
+ The final formatted number is formatted according to the following configuration
399
+ priority, ordered from highest to lowest precedence:
400
+
401
+ . The `format` hash given to `Plurimath::NumberFormatter#localized_number`
402
+ . The `localize_number` string in the creation of a `Plurimath::NumberFormatter`
403
+ . The `localizer_symbols` hash in the creation of a `Plurimath::NumberFormatter`
404
+ . The **default configuration** of the locale of the `Plurimath::NumberFormatter`
405
+
406
+
407
+ [example]
408
+ .Formatting a number to group every 2 digits
409
+ ====
410
+ [source, ruby]
411
+ ----
412
+ formatter = Plurimath::NumberFormatter.new(:en)
413
+ formatted_number = formatter.localized_number(
414
+ "1234567.89",
415
+ format: {
416
+ group_digits: 2,
417
+ # other support options
418
+ }
419
+ )
420
+ # => "1,23,45,67.89"
421
+ ----
422
+ ====
423
+
424
+
425
+ ==== Creating a number formatter
426
+
427
+ The `NumberFormatter` is used to format numbers based on the locale and the
428
+ formatting configuration provided.
429
+
430
+ Syntax:
431
+
432
+ .Syntax for creating a `Plurimath::NumberFormatter` object
433
+ [source,ruby]
434
+ ----
435
+ formatter = Plurimath::NumberFormatter.new(
436
+ <locale-symbol>, # mandatory <1>
437
+ localize_number: <localize-string>, # optional <2>
438
+ localizer_symbols: <format-hash>, # optional <3>
439
+ precision: <precision-number>, # optional <4>
440
+ )
441
+ ----
442
+ <1> Locale to be used for number formatting.
443
+ <2> String pattern to define the number formatting.
444
+ <3> Hash containing relevant options for number formatting.
445
+ <4> Number of decimal places to round.
446
+
447
+ Where,
448
+
449
+ `<locale-symbol>`:: (optional, default `:en`) The locale to be used for number formatting.
450
+ Accepted values are listed in the
451
+ `Plurimath::Formatter::SupportedLocales::LOCALES` constant.
452
+
453
+ `localize_number: <localize-string>`:: (optional, default `nil`) A string containing a specific
454
+ sequence of characters that defines the number formatting. Use either
455
+ `localize_number` or `localizer_symbols` to set the number formatting pattern.
456
+ +
457
+ See <<localize_number,`localize_number`>> for details.
458
+
459
+ `localizer_symbols: <format-hash>`:: (optional, default `{}`) A hash containing the relevant
460
+ options for number formatting. Use either `localize_number` or
461
+ `localizer_symbols` to set the number formatting pattern.
462
+ +
463
+ See <<localizer_symbols,format options hash>> for details.
464
+
465
+ `precision: <precision-number>`:: (optional, default `nil`)
466
+ Number of decimal places to round. Accepts an integer value.
467
+ +
468
+ .Specifying a precision of 6 digits
469
+ [example]
470
+ ====
471
+ "32232.232" => "32232.232000"
472
+ ====
473
+
474
+
475
+ .Creating a `Plurimath::NumberFormatter` object using the `:en` locale
476
+ [example]
477
+ ====
478
+ [source,ruby]
479
+ ----
480
+ formatter = Plurimath::NumberFormatter.new(:en)
481
+ # => #<Plurimath::NumberFormatter:0x00007f8b1b8b3b10 @locale=:en>
482
+ ----
483
+ ====
484
+
485
+
486
+ ==== Configuring the number formatter
487
+
488
+ The `Plurimath::NumberFormatter` object can be configured using either the
489
+ `localize_number` or `localizer_symbols` options.
490
+
491
+
492
+ [[localizer_symbols]]
493
+ ===== Via "format options" using `localizer_symbols`
494
+
495
+ The `localizer_symbols` key is used to set the number formatting pattern
496
+ through a Hash object containing specified options.
497
+
498
+ This Hash object is called the "format options Hash".
499
+
500
+ Available options are explained below.
501
+
502
+ NOTE: Each option takes an input of a certain specified type (`String` or
503
+ `Numeric`). Using an input type other than the specified type will result in
504
+ errors or incorrect output.
505
+
506
+ The values passed to `localizer_symbols` persist as long as the initialized
507
+ `NumberFormatter` instance is accessible. It is therefore useful in scenarios
508
+ when configuration will be static or changes are not required very often.
509
+
510
+
511
+ `decimal`:: (`String` value)
512
+ Symbol to use for the decimal point. Accepts a character.
513
+ +
514
+ .Using the ',' "comma" symbol as the decimal point
515
+ [example]
516
+ ====
517
+ "32232.232" => "32232,232"
518
+ ====
519
+ +
520
+ .Using the '.' "full stop" symbol as the decimal point
521
+ [example]
522
+ ====
523
+ "32232.232" => "32232.232"
524
+ ====
525
+
526
+ `digit_count`:: (`Numeric` value)
527
+ Total number of digits to render, with the value truncated.
528
+ Accepts an integer value.
529
+ +
530
+ .Specifying a total of 6 digits in rendering the number
531
+ [example]
532
+ ====
533
+ "32232.232" => "32232.2"
534
+ ====
535
+
536
+
537
+ `group`:: (`String` value)
538
+ Delimiter to use between groups of digits specified in `group_digits`. Accepts a
539
+ character. (default is not to group digits.)
540
+ +
541
+ .Using the unicode thin space (THIN SPACE, U+2009) as the grouping delimiter
542
+ [example]
543
+ ====
544
+ "32232.232" => "32 232.232"
545
+ ====
546
+
547
+
548
+ `group_digits`:: (`Numeric` value)
549
+ Number of digits to group the integer portion, grouping from right to left.
550
+ Accepts an integer value. (default is 3 in most locales.)
551
+ +
552
+ .Using the unicode thin space as the grouping delimiter, and grouping every 2 digits
553
+ [example]
554
+ ====
555
+ "32232.232" => "3 22 32.232"
556
+ ====
557
+
558
+ `fraction_group`:: (`String` value)
559
+ Delimiter to use between groups of fractional digits specified in
560
+ `fraction_group_digits`. Accepts a character.
561
+ +
562
+ .Using the unicode thin space as the fraction grouping delimiter
563
+ [example]
564
+ ====
565
+ "32232.232131" => "32232.232 131".
566
+ ====
567
+
568
+ `fraction_group_digits`:: (`Numeric` value)
569
+ Number of digits in each group of fractional digits, grouping from left to
570
+ right. Accepts an integer value.
571
+ +
572
+ .Using the unicode thin space as the fraction grouping delimiter, and grouping every 2 fraction digits
573
+ [example]
574
+ ====
575
+ "32232.232131" => "32232.23 21 31"
576
+ ====
577
+
578
+ `significant`:: (`Numeric` value)
579
+ Sets the number of significant digits to show, with the value rounded.
580
+
581
+ `notation`:: (`String` value)
582
+ Specifies the mathematical notation to be used. Accepts the following values.
583
+
584
+ `e`::: Use exponent notation.
585
+ +
586
+ .Example of using exponent notation
587
+ [example]
588
+ ====
589
+ 1.23456789e8
590
+ ====
591
+
592
+ `scientific`::: Use scientific notation.
593
+ +
594
+ .Example of using scientific notation
595
+ [example]
596
+ ====
597
+ 1.23456789 × 10⁸
598
+ ====
599
+
600
+ `engineering`::: Use engineering notation, where the exponent of ten is always
601
+ selected to be divisible by three to match the common metric prefixes.
602
+ +
603
+ .Example of using engineering notation
604
+ [example]
605
+ ====
606
+ 123.456789 × 10⁶
607
+ ====
608
+
609
+ `e`:: (`String` value)
610
+ Symbol to use for exponents in E notation (default value `E`). (used in the
611
+ mode: `e` only).
612
+ +
613
+ .Using the lowercase 'e' symbol as the exponent symbol
614
+ [example]
615
+ ====
616
+ ----
617
+ 3.2232232e5
618
+ ----
619
+ ====
620
+
621
+ `times`:: (`String` value)
622
+ Symbol to use for multiplication where required by the notation (used in the
623
+ modes: `scientific` and `engineering`). Defaults to `×`.
624
+ +
625
+ .Using the '·' "middle dot" symbol as the multiplication symbol
626
+ [example]
627
+ ====
628
+ ----
629
+ 32.232232 · 104
630
+ ----
631
+ ====
632
+
633
+ `exponent_sign`:: (`String` value)
634
+ Whether to use a plus sign to indicate positive exponents, in exponent-based
635
+ notation (used in the modes: `e`, `scientific`, `engineering`). Legal values
636
+ are:
637
+
638
+ `plus`::: The `+` symbol is used.
639
+ +
640
+ .Using the plus sign to indicate positive exponents
641
+ [example]
642
+ ====
643
+ ----
644
+ 32.232232 × 10⁺⁴
645
+ ----
646
+ ====
647
+
648
+ These options are to be grouped under a single Hash object.
649
+
650
+ .Format options Hash for `localizer_symbols`
651
+ [source,ruby]
652
+ ----
653
+ {
654
+ decimal: ",", # replaces the decimal point with the passed string
655
+ group_digits: 2, # groups integer part into passed integer
656
+ group: "'", # places the string between grouped parts of the integer
657
+ fraction_group_digits: 3, # groups fraction part into passed integer
658
+ fraction_group: ",", # places the string between grouped parts of the fraction
659
+ }
660
+ ----
661
+
662
+
663
+ [[localize_number]]
664
+ ===== Via the `localize_number` option
665
+
666
+ The `localize_number` option accepts a formatting pattern specified as a string,
667
+ using the hash symbol `#` to represent a digit placeholder.
668
+
669
+ The `localize_number` option is useful when you want to format numbers in a
670
+ specific way that is not covered by the `localizer_symbols` option.
671
+ // TODO When is that?
672
+
673
+ A sample value of `\#,\##0.\### \###` is interpreted as the following
674
+ configuration in the <<localizer_symbols,format options hash>>:
675
+
676
+ `group`::
677
+ This parameter is set to the very first non-hash character before 0.
678
+ If there is no non-hash character before `#`+`0`, then the default group
679
+ delimiter will be nil.
680
+ +
681
+ In this example, it is `,`.
682
+
683
+ `group_digits`::
684
+ This parameter is set to the "count of all hashes + 1" (including the zero).
685
+ Minimum 1 hash symbol is required.
686
+ +
687
+ In this example, `##0` sets the value to 3.
688
+
689
+ `decimal`::
690
+ This parameter is set to the character immediately to the right of `0`.
691
+ This is mandatory.
692
+ +
693
+ In this example, it is `.`.
694
+
695
+ `fraction_group_digits`::
696
+ This parameter is set to "count of all the hashes right next to decimal".
697
+ Minimum 1 hash symbol is required.
698
+ +
699
+ In our example, '\###' sets the value to 3.
700
+
701
+ `fraction_group`::
702
+ This parameter is set to the first character after `fraction_group_digits`.
703
+ If there is no non-hash character after `fraction_group_digits`, it is
704
+ set to nil.
705
+ +
706
+ In this example it is `' '` (a space).
707
+
708
+
709
+ .Formatting a number using the `localize_number` option
710
+ [example]
711
+ ====
712
+ [source,ruby]
713
+ ----
714
+ formatter = Plurimath::NumberFormatter.new(:en, localize_number: "#,##0.### ###")
715
+ formatter.localized_number("1234.56789")
716
+ # => "1,234.568 9"
717
+ ----
718
+ ====
719
+
720
+
721
+
722
+ ==== Formatting a number using `NumberFormatter`
723
+
724
+ The `localized_number` method is used to format a number given a
725
+ `NumberFormatter` instance.
726
+
727
+ Syntax:
728
+
729
+ .Syntax for `localized_number`
730
+ [source,ruby]
731
+ ----
732
+ formatter.localized_number(
733
+ <number>, # mandatory <1>
734
+ locale: <locale-symbol>, # optional <2>
735
+ precision: <precision-number>, # optional <3>
736
+ format: <format-hash> # optional <4>
737
+ )
738
+ ----
739
+ <1> The number to be formatted.
740
+ <2> The locale to be used for number formatting.
741
+ <3> The number of decimal places to round the number to.
742
+ <4> Hash containing the relevant options for number formatting.
743
+
744
+ Where,
745
+
746
+ `<number>`:: (mandatory) The number to be formatted. Value should be a Numeric,
747
+ i.e. Integer, Float, or BigDecimal. If not provided, an `ArgumentError` will be
748
+ raised.
749
+
750
+ `locale: <locale-symbol>`:: (optional) The locale to be used for number formatting.
751
+ Value is a symbol.
752
+ Overrides the locale set during the creation of the `NumberFormatter` object. If
753
+ not provided, the locale of the `NumberFormatter` instance will be used.
754
+
755
+ `precision: <precision-number>`:: (optional) The number of decimal places to round the
756
+ number to. If not provided, the precision of the `NumberFormatter` instance will
757
+ be used.
758
+
759
+ `format: <format-hash>`:: (optional, default `{}`) A Hash containing the relevant
760
+ options for number formatting, that overrides the `localizer_symbols`
761
+ configuration of the `NumberFormatter`.
762
+ Takes a Hash in the form of the <<localizer_symbols,format options hash>>.
763
+
764
+ `precision: <precision-number>`::
765
+ Number of decimal places to round. Accepts an integer value.
766
+ +
767
+ .Specifying a precision of 6 digits
768
+ [example]
769
+ ====
770
+ "32232.232" => "32232.232000"
771
+ ====
772
+
773
+
774
+ .Formatting a number using the `localized_number` method for the English locale
775
+ [example]
776
+ ====
777
+ [source,ruby]
778
+ ----
779
+ formatter = Plurimath::NumberFormatter.new(:en)
780
+ formatter.localized_number("1234.56789")
781
+ # => "1,234.56789"
782
+ ----
783
+ ====
784
+
785
+ .Formatting a number using the `localized_number` method for the French locale
786
+ [example]
787
+ ====
788
+ [source,ruby]
789
+ ----
790
+ formatter = Plurimath::NumberFormatter.new(:fr)
791
+ formatter.localized_number("1234.56789")
792
+ # => "1 234,56789"
793
+ ----
794
+ ====
795
+
796
+
797
+ The locale and precision set in the `NumberFormatter` can be overridden by
798
+ passing the `locale` and `precision` options to the `localized_number` method.
799
+
800
+ .Overriding locale and precision in `localized_number`
801
+ [example]
802
+ ====
803
+ [source,ruby]
804
+ ----
805
+ formatter = Plurimath::NumberFormatter.new(:en)
806
+ formatter.localized_number("1234.56789", locale: :de, precision: 6)
807
+ # => "1.234,567890"
808
+ ----
809
+ ====
810
+
811
+
812
+ ==== Overriding specified `NumberFormatter` options using the `format` key
813
+
814
+ The `format` option is used to override the specified configuration of the
815
+ `NumberFormatter` object.
816
+
817
+ It expects a Hash in the form of the <<localizer_symbols,format options hash>>.
818
+
819
+ .Using the `format` key to override the decimal point symbol with `x`
820
+ [example]
821
+ ====
822
+ [source,ruby]
823
+ ----
824
+ formatter = Plurimath::NumberFormatter.new(:en)
825
+ formatter.localized_number(
826
+ "1234.56789",
827
+ format: {
828
+ decimal: "x",
829
+ # other supported options
830
+ }
831
+ )
832
+ # => "1,234x56789"
833
+ ----
834
+ ====
835
+
836
+ .Using the `format` key to group numbers in 2 digits
837
+ [example]
838
+ ====
839
+ [source,ruby]
840
+ ----
841
+ formatter = Plurimath::NumberFormatter.new(:en)
842
+ formatter.localized_number(
843
+ "1234567.89",
844
+ format: {
845
+ group_digits: 2,
846
+ # other supported options
847
+ }
848
+ )
849
+ # => "1,23,45,67.89"
850
+ ----
851
+ ====
852
+
853
+ .Formatting a number using the `format` key in the `localized_number` method
854
+ [example]
855
+ ====
856
+ [source,ruby]
857
+ ----
858
+ formatter = Plurimath::NumberFormatter.new(:en)
859
+ formatter.localized_number(
860
+ "1234.56789",
861
+ format: {
862
+ decimal: "x",
863
+ group_digits: 2,
864
+ group: "'",
865
+ fraction_group_digits: 3,
866
+ fraction_group: ","
867
+ }
868
+ )
869
+ # => "12'34x567,89"
870
+ ----
871
+ ====
872
+
873
+
874
+ === Supported locales
875
+
876
+ Plurimath supports the following locales for number formatting. The locale
877
+ values are sourced from the https://cldr.unicode.org[Unicode CLDR] repository.
878
+
879
+ The list of locales and their values are given in the file
880
+ `lib/plurimath/formatter/supported_locales.rb`.
881
+
882
+ The locales and their values can be obtained through the following code.
883
+
884
+ .Getting the supported locales and their default values
885
+ [source,ruby]
886
+ ----
887
+ Plurimath::Formatter::SupportedLocales::LOCALES[:en]
888
+ # => { decimal: ".", group: "," }
889
+ ----
890
+
891
+ .Locales supported by Plurimath (delimiters wrapped in double quotes)
892
+ |===
893
+ | Locale | Decimal delimiter | Group delimiter
894
+
895
+ | `sr-Cyrl-ME` | `","` | `"."`
896
+ | `sr-Latn-ME` | `","` | `"."`
897
+ | `zh-Hant` | `"."` | `","`
898
+ | `en-001` | `"."` | `","`
899
+ | `en-150` | `"."` | `","`
900
+ | `pt-PT` | `","` | `" "`
901
+ | `nl-BE` | `","` | `"."`
902
+ | `it-CH` | `"."` | `"’"`
903
+ | `fr-BE` | `","` | `" "`
904
+ | `fr-CA` | `","` | `" "`
905
+ | `fr-CH` | `","` | `" "`
906
+ | `de-AT` | `","` | `" "`
907
+ | `de-CH` | `"."` | `"’"`
908
+ | `en-AU` | `"."` | `","`
909
+ | `en-CA` | `"."` | `","`
910
+ | `en-GB` | `"."` | `","`
911
+ | `en-IE` | `"."` | `","`
912
+ | `en-IN` | `"."` | `","`
913
+ | `en-NZ` | `"."` | `","`
914
+ | `en-SG` | `"."` | `","`
915
+ | `en-US` | `"."` | `","`
916
+ | `en-ZA` | `"."` | `","`
917
+ | `es-419` | `"."` | `","`
918
+ | `es-AR` | `","` | `"."`
919
+ | `es-CO` | `","` | `"."`
920
+ | `es-MX` | `"."` | `","`
921
+ | `es-US` | `"."` | `","`
922
+ | `fil` | `"."` | `","`
923
+ | `af` | `","` | `" "`
924
+ | `ar` | `"٫"` | `"٬"`
925
+ | `az` | `","` | `"."`
926
+ | `be` | `","` | `" "`
927
+ | `bg` | `","` | `" "`
928
+ | `bn` | `"."` | `","`
929
+ | `bo` | `"."` | `","`
930
+ | `bs` | `","` | `"."`
931
+ | `ca` | `","` | `"."`
932
+ | `cs` | `","` | `" "`
933
+ | `cy` | `"."` | `","`
934
+ | `da` | `","` | `"."`
935
+ | `de` | `","` | `"."`
936
+ | `el` | `","` | `"."`
937
+ | `en` | `"."` | `","`
938
+ | `eo` | `","` | `" "`
939
+ | `es` | `","` | `"."`
940
+ | `et` | `","` | `" "`
941
+ | `eu` | `","` | `"."`
942
+ | `fa` | `"٫"` | `"٬"`
943
+ | `fi` | `","` | `" "`
944
+ | `fr` | `","` | `" "`
945
+ | `ga` | `"."` | `","`
946
+ | `gl` | `","` | `"."`
947
+ | `gu` | `"."` | `","`
948
+ | `he` | `"."` | `","`
949
+ | `hi` | `"."` | `","`
950
+ | `hr` | `","` | `"."`
951
+ | `hu` | `","` | `" "`
952
+ | `hy` | `","` | `" "`
953
+ | `id` | `","` | `"."`
954
+ | `is` | `","` | `"."`
955
+ | `it` | `","` | `"."`
956
+ | `ja` | `"."` | `","`
957
+ | `ka` | `","` | `" "`
958
+ | `kk` | `","` | `" "`
959
+ | `km` | `","` | `"."`
960
+ | `kn` | `"."` | `","`
961
+ | `ko` | `"."` | `","`
962
+ | `lo` | `","` | `"."`
963
+ | `lt` | `","` | `" "`
964
+ | `lv` | `","` | `" "`
965
+ | `mk` | `","` | `"."`
966
+ | `mr` | `"."` | `","`
967
+ | `ms` | `"."` | `","`
968
+ | `mt` | `"."` | `","`
969
+ | `my` | `"."` | `","`
970
+ | `nb` | `","` | `" "`
971
+ | `nl` | `","` | `"."`
972
+ | `pl` | `","` | `" "`
973
+ | `pt` | `","` | `"."`
974
+ | `ro` | `","` | `"."`
975
+ | `ru` | `","` | `" "`
976
+ | `sk` | `","` | `" "`
977
+ | `sl` | `","` | `"."`
978
+ | `sq` | `","` | `" "`
979
+ | `sr` | `","` | `"."`
980
+ | `sv` | `","` | `" "`
981
+ | `sw` | `"."` | `","`
982
+ | `ta` | `"."` | `","`
983
+ | `th` | `"."` | `","`
984
+ | `tr` | `","` | `"."`
985
+ | `uk` | `","` | `" "`
986
+ | `ur` | `"."` | `","`
987
+ | `vi` | `","` | `"."`
988
+ | `xh` | `"."` | `" "`
989
+ | `zh` | `"."` | `","`
990
+ | `zu` | `"."` | `","`
991
+
992
+ |===
993
+
994
+
995
+
996
+
997
+ === Formatting numbers in a formula
998
+
999
+ ==== General
1000
+
1001
+ Plurimath supports number formatting within formulas for all supported
1002
+ languages. This feature allows you to apply custom number formatting when
1003
+ converting formulas to any of the supported format.
1004
+
1005
+ NOTE: For details, check out our blog post:
1006
+ link:https://www.plurimath.org/blog/2024-09-16-formula-number-formatting/[**Number formatting now supported in formulas across all math representation languages**].
1007
+
1008
+
1009
+ The steps to format numbers within a formula are:
1010
+
1011
+ . Create a number formatter that can be configured;
1012
+
1013
+ . Apply the number formatter to a formula through the `Formula.to_{format}`
1014
+ method using a `formatter` option, which serializes the formula into an math
1015
+ representation language.
1016
+
1017
+ The formatter should be an instance of `Plurimath::NumberFormatter` or a custom
1018
+ formatter derived from `Plurimath::Formatter::Standard`.
1019
+
1020
+ The quick example below demonstrates how to format a number in a formula.
1021
+
1022
+ [example]
1023
+ .Applying number formatting to a formula in LaTeX math
1024
+ ====
1025
+ The following code applies number formatting to a LaTeX math formula.
1026
+
1027
+ [source,ruby]
1028
+ ----
1029
+ formula = Plurimath::Math.parse('\sum_{i=1}^{10000} i^2121221', :latex) <1>
1030
+ formatter = Plurimath::Formatter::Standard.new <2>
1031
+ formula.to_latex(formatter: formatter) <3>
1032
+ # => '\sum_{i = 1}^{10,000} i^{2,121,221}'
1033
+ ----
1034
+ <1> The formula is parsed into a `Formula` object using the
1035
+ `Plurimath::Math.parse` method.
1036
+ <2> A `Plurimath::Formatter` is created.
1037
+ <3> The `Formula.to_latex` method is called with the `formatter` option to
1038
+ format the formula.
1039
+ ====
1040
+
1041
+ [example]
1042
+ .Applying number formatting to an AsciiMath formula in MathML
1043
+ ====
1044
+ [source,ruby]
1045
+ ----
1046
+ formula = Plurimath::Math.parse("e^(i*pi) + 1.1 = 0.2", :asciimath)
1047
+ custom_formatter = Plurimath::Formatter::Standard.new(
1048
+ locale: :fr,
1049
+ options: { number_sign: :plus },
1050
+ precision: 3
1051
+ )
1052
+ print formula.to_mathml(formatter: custom_formatter)
1053
+ # <math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
1054
+ # <mstyle displaystyle="true">
1055
+ # <msup>
1056
+ # <mi>e</mi>
1057
+ # <mrow>
1058
+ # <mi>i</mi>
1059
+ # <mo>&#x22c5;</mo>
1060
+ # <mi>&#x3c0;</mi>
1061
+ # </mrow>
1062
+ # </msup>
1063
+ # <mo>+</mo>
1064
+ # <mn>+1.100</mn>
1065
+ # <mo>=</mo>
1066
+ # <mn>+0.200</mn>
1067
+ # </mstyle>
1068
+ # </math>
1069
+ ----
1070
+ ====
1071
+
1072
+
1073
+ ==== Defining a number formatter
1074
+
1075
+ A "number formatter" is a class that formats numbers in a specific way. It
1076
+ contains the configuration for formatting numbers, such as the number of digits
1077
+ in a group, the decimal separator, and the group separator.
1078
+
1079
+ Plurimath offers a standard formatter class called
1080
+ `Plurimath::Formatter::Standard` that includes a comprehensive
1081
+ link:#standard_configuration[standard configuration].
1082
+
1083
+ .Creating a standard `Plurimath::Formatter::Standard` object
1084
+ [source,ruby]
1085
+ ----
1086
+ > formatter = Plurimath::Formatter::Standard.new <1>
1087
+ ----
1088
+ <1> Creates a `Plurimath::Formatter` object that uses standard configuration.
1089
+
1090
+
1091
+ The number formatting configuration can be changed in these ways:
1092
+
1093
+ . Pass options to the `Plurimath::Formatter::Standard` class initializer
1094
+ (with options explained in the
1095
+ https://www.plurimath.org/blog/2024-07-09-number-formatter[number formatter blog post]).
1096
+
1097
+ . Create a custom formatter inheriting from the `Plurimath::Formatter::Standard` class.
1098
+
1099
+
1100
+
1101
+ ==== Changing number formatting configuration
1102
+
1103
+ The typical way to change the number formatting configuration is to create a
1104
+ `Plurimath::Formatter::Standard` object with the desired configuration options.
1105
+
1106
+ There are two types of number formatting configuration to change:
1107
+
1108
+ . Arguments passed to the `Plurimath::Formatter::Standard` class initializer.
1109
+
1110
+ . Overriding options through the `options` argument.
1111
+
1112
+ The arguments are:
1113
+
1114
+ `locale`:: (default: `:en` for English) a symbol or string value. The supported
1115
+ locales are listed in the link:/blog/2024-07-09-number-formatter[number formatter blog post].
1116
+
1117
+ `options`:: (default: empty) a hash of options (`localizer_symbols`). The options
1118
+ are listed in the link:/blog/2024-07-09-number-formatter[number formatter blog post].
1119
+
1120
+ `format_string`:: (default: `nil`, disabled) a string value (localize_number)
1121
+
1122
+ `precision`:: (default: `nil`, disabled) an integer value.
1123
+
1124
+
1125
+ [example]
1126
+ .Passing arguments to the `Plurimath::Formatter::Standard` class initializer
1127
+ ====
1128
+ [source,ruby]
1129
+ ----
1130
+ > options = {
1131
+ fraction_group_digits: 2,
1132
+ fraction_group: ".",
1133
+ group_digits: 2,
1134
+ decimal: ";",
1135
+ group: ",",
1136
+ }
1137
+
1138
+ > formatter = Plurimath::Formatter::Standard.new(locale: :hy, options: options, precision: 2)
1139
+ # format_string: <string value> if provided
1140
+
1141
+ > Plurimath::Math.parse('2121221.3434', :latex).to_latex(formatter: formatter)
1142
+ # => '2,12,12,21;34'
1143
+ ----
1144
+
1145
+ The `precision = 2` option in the initializer causes the formatted value to have
1146
+ decimal places truncated from 4 to 2.
1147
+ ====
1148
+
1149
+
1150
+
1151
+ ==== Creating a custom formatter
1152
+
1153
+ In cases where the standard formatter's available options do not meet the needs
1154
+ for number presentation, a custom formatter can be created to apply new
1155
+ mechanisms of formatting numbers.
1156
+
1157
+ The custom formatter is to be subclassed from `Plurimath::Formatter::Standard`.
1158
+
1159
+ .Creating a custom formatter
1160
+ [source,ruby]
1161
+ ----
1162
+ class MyCustomFormatter < Plurimath::Formatter::Standard <1>
1163
+ def initialize(locale:, precision:, options:, format_string:) <2>
1164
+ super
1165
+ end
1166
+ end
1167
+ ----
1168
+ <1> The custom formatter class inherits from `Plurimath::Formatter::Standard`.
1169
+ <2> The arguments can be overridden in the `initialize` method.
1170
+
1171
+ The default options of the custom formatter are set using the
1172
+ `set_default_options` method.
1173
+
1174
+ .Syntax to override the `set_default_options` method
1175
+ [source,ruby]
1176
+ ----
1177
+ class MyCustomFormatter < Plurimath::Formatter::Standard
1178
+ def initialize(locale:, precision:, options:, format_string:)
1179
+ super
1180
+ end
1181
+
1182
+ def set_default_options(options = {}) <1>
1183
+ options = {
1184
+ fraction_group_digits: 2,
1185
+ fraction_group: ".",
1186
+ ...
1187
+ }
1188
+ end
1189
+ end
1190
+ ----
1191
+ <1> The `set_default_options` method is overridden to set the default options.
1192
+ The shown options are ones inherited from the `Plurimath::Formatter::Standard`
1193
+ class, but additional ones understood by the class can be set.
1194
+
1195
+ It is used in the following manner.
1196
+
1197
+ .Creating a `CustomFormatter` object and using it to format numbers in a formula
1198
+ [example]
1199
+ ====
1200
+ [source,ruby]
1201
+ ----
1202
+ class MyCustomFormatter < Plurimath::Formatter::Standard
1203
+ def initialize(locale: :fr)
1204
+ super
1205
+ end
1206
+
1207
+ def set_default_options(options = {})
1208
+ {
1209
+ fraction_group_digits: 2,
1210
+ fraction_group: ".",
1211
+ group_digits: 2,
1212
+ decimal: ";",
1213
+ group: ",",
1214
+ ...
1215
+ }
1216
+ end
1217
+ end
1218
+
1219
+ > formula = Plurimath::Math.parse('\sum_{i=1}^{1000.001} i^2121221.3434', :latex)
1220
+ # => Plurimath::Math::Formula...
1221
+ > formula.to_latex(formatter: formatter)
1222
+ # => '\sum_{i = 1}^{10,00;00.1} i^{2,12,12,21;34.34}'
1223
+ > formula.to_asciimath(formatter: formatter)
1224
+ # => 'sum_(i = 1)^(10,00;00.1) i^(2,12,12,21;34.34)'
1225
+ ----
1226
+ ====
1227
+
1228
+
1229
+ [[standard_configuration]]
1230
+ === Default number formatting configuration
1231
+
1232
+ The default configuration for formatting numbers is as follows, set in the
1233
+ `Plurimath::Formatter::Standard` class.
1234
+
1235
+ |===
1236
+ |Option key |Description |Value
1237
+
1238
+ |`locale`
1239
+ |The locale used for number formatting
1240
+ |`:en`
1241
+
1242
+ |`fraction_group_digits`
1243
+ |The number of digits in each group of the fraction part
1244
+ |`3`
1245
+
1246
+ |`exponent_sign`
1247
+ |The sign used for the exponent part of the number
1248
+ |`"plus"`
1249
+
1250
+ |`fraction_group`
1251
+ |The character used to separate groups of digits in the fraction part
1252
+ |`"'"`
1253
+
1254
+ |`notation`
1255
+ |The notation used for the number formatting
1256
+ |`:basic`
1257
+
1258
+ |`group_digits`
1259
+ |The number of digits in each group of the integer part
1260
+ |`3`
1261
+
1262
+ |`significant`
1263
+ |The number of significant digits to display
1264
+ |`0`
1265
+
1266
+ |`digit_count`
1267
+ |The number of digits to display
1268
+ |`0`
1269
+
1270
+ |`precision`
1271
+ |The number of decimal places to display
1272
+ |`0`
1273
+
1274
+ |`decimal`
1275
+ |The character used as the decimal separator
1276
+ |`"."`
1277
+
1278
+ |`group`
1279
+ |The character used to separate groups of digits in the integer part
1280
+ |`","`
1281
+
1282
+ |`times`
1283
+ |The character used for multiplication
1284
+ |`"x"`
1285
+
1286
+ |`e`
1287
+ |The character used for exponentiation
1288
+ |`"e"`
1289
+
1290
+ |===
1291
+
1292
+
1293
+
309
1294
 
310
1295
  == Math parse trees
311
1296