From 4de75fb2a73c61a809e86e8decad9282215214e0 Mon Sep 17 00:00:00 2001 From: Ulf Adams Date: Sun, 7 Jul 2019 20:30:31 +0200 Subject: [PATCH] Additional README notes --- README.md | 164 +++++++++++++++++++++++++++--------------------------- 1 file changed, 83 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index e710953b..11d0ac3c 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ posed by White and Steele [1], for which they described an algorithm called "Dragon". It was subsequently improved upon with algorithms that also had dragon-themed names. I followed in the same vein using the japanese word for dragon, Ryu. In general, all these algorithms should produce identical output -given identical input. +given identical input, and this is checked when running the benchmark program. The C implementation of Ryu is in the ryu/ directory. The Java implementations are RyuFloat and RyuDouble under src/main/java/. Both cover 32 and 64-bit @@ -88,7 +88,18 @@ implementations, printf provides three floating-point specific formatters, Ryu Printf implements %f and %e formatting in a way that should be drop-in compatible with most implementations of printf, although it currently does not -implement any formatting flags other than precision. +implement any formatting flags other than precision. The benchmark program +verifies that the output matches exactly, and outputs a warning if not. Any +unexpected output from the benchmark indicates a difference in output. + +*Note* that old versions of MSVC ship with a printf implementation that has a +confirmed bug: it does not always round the last digit correctly. + +*Note* that msys cuts off the output after ~17 digits, and therefore generally +differs from Ryu Printf output for precision values larger than 17. + +*Note* that the output for NaN values can differ between implementations; we use +ifdefs in an attempt to match platform output. According to our benchmarks, Ryu Printf compares favorably with the following implementations of printf for precision parameters 1, 10, 100, and 1000: @@ -124,6 +135,13 @@ To build Ryu Printf, run $ bazel build //ryu:ryu_printf ``` +### Big-Endian Architectures +The C implementation of Ryu should work on big-endian architectures provided +that the floating point type and the corresponding integer type use the same +endianness. + +There are no concerns around endianness for the Java implementation. + ### Building with a Custom Compiler You can select a custom C++ compiler by setting the CC environment variable (e.g., on Ubuntu, run `export CC=clang-3.9`). @@ -145,9 +163,69 @@ You can run both C and Java tests with $ bazel test //ryu/... //src/... ``` -### Benchmarks -#### Ryu + +## Ryu: Additional Notes + +### Jaffer +The code given by Jaffer in the original paper does not come with a license +declaration. Instead, we're using code found on GitHub, which contains a +license declaration by Jaffer. Compared to the original code, this +implementation no longer outputs incorrect values for negative numbers. + +We provide a binary to find differences between Ryu and the Jaffer / Jdk +implementations: +``` +$ bazel run //src/main/java/info/adams/ryu/analysis:FindDifferences -- +``` + +Add the `-mode=csv` option to get all the discovered differences as a CSV. Use +`-mode=latex` instead to get a latex snippet of the first 20. Use +`-mode=summary` to only print the number of discovered differences (this is the +default mode). + +### Computing Required Lookup Table Sizes +You can compute the required lookup table sizes with: +``` +$ bazel run //src/main/java/info/adams/ryu/analysis:ComputeTableSizes -- +``` + +Add `-v` to get slightly more verbose output. + +### Computing Required Bit Sizes +You can compute the required bit sizes with: +``` +$ bazel run //src/main/java/info/adams/ryu/analysis:ComputeRequiredBitSizes -- +``` + +Add the `-128` and `-256` flags to also cover 128- and 256-bit numbers. This +could take a while - 128-bit takes ~20 seconds on my machine while 256-bit takes +a few hours. Add `-v` to get very verbose output. + +### Java: Comparing All Possible 32-bit Values Exhaustively +You can check the slow vs. the fast implementation for all 32-bit floating point +numbers using: +``` +$ bazel run //src/main/java/info/adams/ryu/analysis:ExhaustiveFloatComparison +``` + +This takes ~60 hours to run to completion on an +Intel(R) Core(TM) i7-4770K with 3.50GHz. + +### Java: Comparing All Possible 64-bit Values Exhaustively +You can check the slow vs. the fast implementation for all 64-bit floating point +numbers using: +``` +$ bazel run //src/main/java/info/adams/ryu/analysis:ExtensiveDoubleComparison +``` + +This takes approximately forever, so you will need to interrupt the program. + + + +## Benchmarks + +### Ryu We provide both C and Java benchmark programs. Enable optimization by adding "-c opt" on the command line: @@ -184,7 +262,7 @@ $ bazel build -c opt --jobs=1 //scripts:shortest-{c,java}-{float,double}.pdf The resulting files are `bazel-genfiles/scripts/shortest-{c,java}-{float,double}.pdf`. -#### Ryu Printf +### Ryu Printf We provide a C++ benchmark program that runs against the implementation of ```snprintf``` bundled with the selected C++ compiler. You need to enable optimization using "-c opt" on the command line: @@ -221,79 +299,3 @@ with: ``` $ bazel build -c opt --jobs=1 //scripts:{f,e}-c-double-{1,10,100,1000}.pdf ``` - - -### Ryu: Comparison with Other Implementations - -#### Grisu3 - -Ryu's output should exactly match Grisu3's output. Our benchmark verifies that -the generated numbers are identical. -``` -$ bazel run -c opt //ryu/benchmark -- -64 - Average & Stddev Ryu Average & Stddev Grisu3 -64: 29.806 3.182 103.060 98.717 -``` - -#### Jaffer's Implementation -The code given by Jaffer in the original paper does not come with a license -declaration. Instead, we're using code found on GitHub, which contains a -license declaration by Jaffer. Compared to the original code, this -implementation no longer outputs incorrect values for negative numbers. - -#### Differences between Ryu and Jaffer / Jdk implementations -We provide a binary to find differences between Ryu and the Jaffer / Jdk -implementations: -``` -$ bazel run //src/main/java/info/adams/ryu/analysis:FindDifferences -- -``` - -Add the `-mode=csv` option to get all the discovered differences as a CSV. Use -`-mode=latex` instead to get a latex snippet of the first 20. Use -`-mode=summary` to only print the number of discovered differences (this is the -default mode). - -### Big-Endian Architectures -The C implementation of Ryu should work on big-endian architectures provided -that the floating point type and the corresponding integer type use the same -endianness. - -There are no concerns around endianness for the Java implementation. - -### Computing Required Lookup Table Sizes -You can compute the required lookup table sizes with: -``` -$ bazel run //src/main/java/info/adams/ryu/analysis:ComputeTableSizes -- -``` - -Add `-v` to get slightly more verbose output. - -### Computing Required Bit Sizes -You can compute the required bit sizes with: -``` -$ bazel run //src/main/java/info/adams/ryu/analysis:ComputeRequiredBitSizes -- -``` - -Add the `-128` and `-256` flags to also cover 128- and 256-bit numbers. This -could take a while - 128-bit takes ~20 seconds on my machine while 256-bit takes -a few hours. Add `-v` to get very verbose output. - -### Java: Comparing All Possible 32-bit Values Exhaustively -You can check the slow vs. the fast implementation for all 32-bit floating point -numbers using: -``` -$ bazel run //src/main/java/info/adams/ryu/analysis:ExhaustiveFloatComparison -``` - -This takes ~60 hours to run to completion on an -Intel(R) Core(TM) i7-4770K with 3.50GHz. - -### Java: Comparing All Possible 64-bit Values Exhaustively -You can check the slow vs. the fast implementation for all 64-bit floating point -numbers using: -``` -$ bazel run //src/main/java/info/adams/ryu/analysis:ExtensiveDoubleComparison -``` - -This takes approximately forever, so you will need to interrupt the program. -