Help needed testing decimal package

Hi, I’ve been working on a decimal package: https://github.com/yawaramin/ocaml-decimal (arbitrary-precision floating-point decimals).

I’ve published a very early preview on opam: http://opam.ocaml.org/packages/decimal/

You can try it out:

$ opam install decimal
$ utop
#
  #require "decimal";;
#
  module D = Decimal
  let i = D.of_int
  let s = D.of_string;;
#
  #install_printer D.pp;;
#
  D.(s "0.1" + s "0.2");;
- : D.t = 0.3
# (* default precision is 32 *)
  D.(i 1 / i 3);;
- : D.t = 0.33333333333333333333333333333333

The module is basically a port of the Python decimal module, with some simplifications like, I’m ignoring different types of NaN like negative NaN, quiet NaN, signalling NaN, and just treating them all as NaN. Otherwise I aim to have the same functionality.

What I need help with mainly is porting the Python decimal unit tests: https://github.com/python/cpython/tree/23831a7a90956e38b7d70304bb6afe30d37936de/Lib/test/decimaltestdata . They are written in a plain-text DSL consisting of test cases like:

addx6324 add  0.12  0.01    ->  0.13

And I assume they have an interpreter somewhere that parses and runs these tests as standard Python unit tests.

What I would like to do is to port these tests into plain OCaml. The above test case could look like (e.g. Alcotest):

check string "addx6324" "0.13" D.(to_string (s "0.12" + s "0.01"))

The test DSL has a few more features, like comments and setting and checking flags, but not too much more complex. So I would really appreciate some help with porting them. I was thinking good old regular expressions to do the conversions, but I’m open to suggestions.

5 Likes

It might be worth it to write a small interpreter for it, that way you don’t have to add new tests when the python library does, you can just sync their changes.

But since I have a fetish for regex:
([a-z0-9]+) +add +(['\-\+0-9\.E]+) +(['\-\+0-9\.E]+) +-> +([\-'\+0-9\.E]+)
check string "$1" "$4" D.(to_string (s "$2" + s "$3"))

1 Like

Thanks Ulrik! Yes, I do believe this data file format is simple enough for regex :slight_smile:

I don’t like regex and I’m a big fan of parser combinators, so I actually went ahead and wrote a parser using Angstrom because I was feeling very bored :slight_smile:

I’ve tried it on the latest version of the test files which is located here http://speleotrove.com/decimal/ and it parses everything without issues. The only part that’s missing is parsing the numbers themselves (I left it for last because it looked very annoying to do correctly).

As for actually running the tests, you could either generate some ocaml files from the AST and then run them (possibly easier debugging?), or interpret the AST directly (less error prone).

The source files look generally like this:

version: 2.62

precision:   9
rounding:    half_up
maxExponent: 384
minexponent: -383
extended:    1

addx001 add 1       1       ->  2
addx002 add 2       3       ->  5
addx003 add '5.75'  '3.3'   ->  9.05
addx004 add '5'     '-3'    ->  2
addx005 add '-5'    '-3'    ->  -8
-- ...
rounding: half_even
addx220 add '123456789' 0             -> '123456789'
addx221 add '123456789' 0.000000001   -> '123456789' Inexact Rounded
addx222 add '123456789' 0.000001      -> '123456789' Inexact Rounded
-- ...
precision: 3
rounding: half_up
addx270 add '12345678900000'  9999999999999 ->  '2.23E+13' Inexact Rounded
addx271 add  '9999999999999' 12345678900000 ->  '2.23E+13' Inexact Rounded

The overall structure is basically:

  • initial configuration
  • test cases
  • changes to configuration
  • test cases

So maybe you could render these different configuration/test cases sections as different test suites, each with their own configuration.

2 Likes

Wow! Was not expecting that. Thank you!!! Taking a look now.

OK I think I’ve made a good start on evaluating this parsed format: https://github.com/yawaramin/ocaml-decimal/blob/test/test/decimal_test.ml

Will make more progress tomorrow. Thanks again!

2 Likes