Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates to #15474 Floating-point printing code (SwiftDtoa.cpp) #16178

Merged
merged 1 commit into from
Apr 26, 2018

Conversation

tbkka
Copy link
Contributor

@tbkka tbkka commented Apr 26, 2018

Updates to #15474: This collects a number of changes I've been testing over the
last month.

Changes

  • Bug fix: The single-precision float formatter sometimes
    chose an odd final digit when there was an equally-good
    even choice.

  • Algorithm simplification: The condition for determining
    whether to widen or narrow the interval was more complex than
    necessary. I now simply widen the interval for all even
    significands.

  • Code simplification: I've simplified the single-precision float formatter.
    Eliminating some 32-bit vs. 64-bit conditionals simplified the code in
    exchange for a minor loss of performance (~2%). A simpler power-of-10
    calculation allows more error in that step but does not affect the result.

  • Performance tweaks: Steve Canon pointed out a few places
    where I could avoid some extraneous arithmetic.

I've also rewritten a lot of comments to try to make the exposition
clearer.

Testing Approach

The earlier testing regime focused on testing from first
principles. For example, I verified accuracy by feeding the
result back into the C library strtof, strtod, etc. and
checking round-trip exactness. Unfortunately, this approach
requires many checks for each value, limiting test performance.
It's also difficult to validate last-digit rounding.

For this round of updates, I've instead compared the digit
decompositions to other popular algorithms:

  • David M. Gay's gdtoa library is a robust and well-tested
    implementation based on Dragon4. It supports all formats, but
    is slow. (netlib.org/fp)
  • Grisu3 supports Float and Double. It is fast but incomplete,
    failing on about 1% of all inputs.
    (github.com/google/double-conversion)
  • Errol4 is fast and complete but only supports Double. The
    repository includes an implementation of the enumeration
    algorithm described in the Errol paper.
    (github.com/marcandrysco/errol)

Test Details

The exact tests varied by format:

  • Float: SwiftDtoa now generates the same digits as gdtoa's
    mode 0 for every single-precision Float.

  • Double: Testing against Grisu3 (with fallback to Errol4 when
    Grisu3 failed) greatly improved test performance. This
    allowed me to test 100 trillion (10^14) randomly-selected
    doubles in a reasonable amount of time. I also checked all
    values generated by the Errol enumeration algorithm.

  • Float80: I compared the Float80 output to the gdtoa library
    because neither Grisu3 nor Errol4 yet supports 80-bit extended
    precision. All values generated by the Errol enumeration
    algorithm have been checked, as well as several billion
    randomly-selected values.

This collects a number of changes I've been testing over the
last month.

* Bug fix: The single-precision float formatter did not always
  round the last digit even in cases where there were two
  possible outputs that were otherwise equally good.

* Algorithm simplification: The condition for determining
  whether to widen or narrow the interval was more complex than
  necessary. I now simply widen the interval for all even
  significands.

* Code simplification: The single-precision float formatter now uses fewer
  64-bit features.  This eliminated some 32-bit vs. 64-bit conditionals in
  exchange for a minor loss of performance (~2%).

* Minor performance tweaks: Steve Canon pointed out a few places
  where I could avoid some extraneous arithmetic.

I've also rewritten a lot of comments to try to make the exposition
clearer.

The earlier testing regime focused on testing from first
principles.  For example, I verified accuracy by feeding the
result back into the C library `strtof`, `strtod`, etc. and
checking round-trip exactness.  Unfortunately, this approach
requires many checks for each value, limiting test performance.
It's also difficult to validate last-digit rounding.

For this round of updates, I've instead compared the digit
decompositions to other popular algorithms:
* David M. Gay's gdtoa library is a robust and well-tested
  implementation based on Dragon4.  It supports all formats, but
  is slow. (netlib.org/fp)
* Grisu3 supports Float and Double.  It is fast but incomplete,
  failing on about 1% of all inputs.
  (github.com/google/double-conversion)
* Errol4 is fast and complete but only supports Double.  The
  repository includes an implementation of the enumeration
  algorithm described in the Errol paper.
  (github.com/marcandrysco/errol)

The exact tests varied by format:

* Float: SwiftDtoa now generates the exact same digits as gdtoa
  for every single-precision Float.

* Double: Testing against Grisu3 (with fallback to Errol4 when
  Grisu3 failed) greatly improved test performance.  This
  allowed me to test 100 trillion (10^14) randomly-selected
  doubles in a reasonable amount of time.  I also checked all
  values generated by the Errol enumeration algorithm.

* Float80: I compared the Float80 output to the gdtoa library
  because neither Grisu3 nor Errol4 yet supports 80-bit extended
  precision.  All values generated by the Errol enumeration
  algorithm have been checked, as well as several billion
  randomly-selected values.
@tbkka
Copy link
Contributor Author

tbkka commented Apr 26, 2018

@swift-ci Please benchmark

@tbkka
Copy link
Contributor Author

tbkka commented Apr 26, 2018

@swift-ci Please test

Copy link
Contributor

@stephentyrone stephentyrone left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.

@swift-ci
Copy link
Contributor

!!! Couldn't read commit file !!!

@tbkka tbkka merged commit 924b8e5 into swiftlang:master Apr 26, 2018
@tbkka tbkka deleted the tbkka-floating-point-printing-update branch April 26, 2018 23:32
stephentyrone pushed a commit that referenced this pull request Apr 27, 2018
This collects a number of changes I've been testing over the
last month.

* Bug fix: The single-precision float formatter did not always
  round the last digit even in cases where there were two
  possible outputs that were otherwise equally good.

* Algorithm simplification: The condition for determining
  whether to widen or narrow the interval was more complex than
  necessary. I now simply widen the interval for all even
  significands.

* Code simplification: The single-precision float formatter now uses fewer
  64-bit features.  This eliminated some 32-bit vs. 64-bit conditionals in
  exchange for a minor loss of performance (~2%).

* Minor performance tweaks: Steve Canon pointed out a few places
  where I could avoid some extraneous arithmetic.

I've also rewritten a lot of comments to try to make the exposition
clearer.

The earlier testing regime focused on testing from first
principles.  For example, I verified accuracy by feeding the
result back into the C library `strtof`, `strtod`, etc. and
checking round-trip exactness.  Unfortunately, this approach
requires many checks for each value, limiting test performance.
It's also difficult to validate last-digit rounding.

For this round of updates, I've instead compared the digit
decompositions to other popular algorithms:
* David M. Gay's gdtoa library is a robust and well-tested
  implementation based on Dragon4.  It supports all formats, but
  is slow. (netlib.org/fp)
* Grisu3 supports Float and Double.  It is fast but incomplete,
  failing on about 1% of all inputs.
  (github.com/google/double-conversion)
* Errol4 is fast and complete but only supports Double.  The
  repository includes an implementation of the enumeration
  algorithm described in the Errol paper.
  (github.com/marcandrysco/errol)

The exact tests varied by format:

* Float: SwiftDtoa now generates the exact same digits as gdtoa
  for every single-precision Float.

* Double: Testing against Grisu3 (with fallback to Errol4 when
  Grisu3 failed) greatly improved test performance.  This
  allowed me to test 100 trillion (10^14) randomly-selected
  doubles in a reasonable amount of time.  I also checked all
  values generated by the Errol enumeration algorithm.

* Float80: I compared the Float80 output to the gdtoa library
  because neither Grisu3 nor Errol4 yet supports 80-bit extended
  precision.  All values generated by the Errol enumeration
  algorithm have been checked, as well as several billion
  randomly-selected values.
airspeedswift pushed a commit that referenced this pull request May 7, 2018
)

This collects a number of changes I've been testing over the
last month.

* Bug fix: The single-precision float formatter did not always
  round the last digit even in cases where there were two
  possible outputs that were otherwise equally good.

* Algorithm simplification: The condition for determining
  whether to widen or narrow the interval was more complex than
  necessary. I now simply widen the interval for all even
  significands.

* Code simplification: The single-precision float formatter now uses fewer
  64-bit features.  This eliminated some 32-bit vs. 64-bit conditionals in
  exchange for a minor loss of performance (~2%).

* Minor performance tweaks: Steve Canon pointed out a few places
  where I could avoid some extraneous arithmetic.

I've also rewritten a lot of comments to try to make the exposition
clearer.

The earlier testing regime focused on testing from first
principles.  For example, I verified accuracy by feeding the
result back into the C library `strtof`, `strtod`, etc. and
checking round-trip exactness.  Unfortunately, this approach
requires many checks for each value, limiting test performance.
It's also difficult to validate last-digit rounding.

For this round of updates, I've instead compared the digit
decompositions to other popular algorithms:
* David M. Gay's gdtoa library is a robust and well-tested
  implementation based on Dragon4.  It supports all formats, but
  is slow. (netlib.org/fp)
* Grisu3 supports Float and Double.  It is fast but incomplete,
  failing on about 1% of all inputs.
  (github.com/google/double-conversion)
* Errol4 is fast and complete but only supports Double.  The
  repository includes an implementation of the enumeration
  algorithm described in the Errol paper.
  (github.com/marcandrysco/errol)

The exact tests varied by format:

* Float: SwiftDtoa now generates the exact same digits as gdtoa
  for every single-precision Float.

* Double: Testing against Grisu3 (with fallback to Errol4 when
  Grisu3 failed) greatly improved test performance.  This
  allowed me to test 100 trillion (10^14) randomly-selected
  doubles in a reasonable amount of time.  I also checked all
  values generated by the Errol enumeration algorithm.

* Float80: I compared the Float80 output to the gdtoa library
  because neither Grisu3 nor Errol4 yet supports 80-bit extended
  precision.  All values generated by the Errol enumeration
  algorithm have been checked, as well as several billion
  randomly-selected values.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants