Thanks to visit codestin.com
Credit goes to github.com

Skip to content

accurate float int printing #5766

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

Closed

Conversation

goatchurchprime
Copy link

This is to fix issue #4212 with the minimum change possible.

It has to store a copy of the input float value before it gets divided out by powers of 10, but it runs slightly faster with this benchmark:

t0 = time.ticks_us();  max(str(float(x))  for x in range(500000, 510000));  (time.ticks_us()-t0)*1e-6
  • New 10.1633 seconds
  • Original: 10.84897 seconds

This is because the implementation from @dhylands https://github.com/dhylands/format-float does a floating point multiplication (by ten) for each digit, and my fix deals with the integer part of the number using only integer arithmetic.

I think there is scope for an overall faster implementation just using int32 arithmetic, but one would have to start by decoding the bit layout of the float into its mantissa and exponent, rather than interacting with value using normal arithmetic functions that do not depend on its encoding -- but since MicroPython is already bit packing and unpacking these values, this wouldn't make it any more dependent.

One advantage of any float32 format conversion is it's possible to exhaustively test every single combination of bits (there's only 4 billion of them) in just a few hours.

@dpgeorge dpgeorge added the py-core Relates to py/ directory in source label Mar 17, 2020
@dpgeorge
Copy link
Member

Thanks for the contribution. The formatting of floats is a relatively frequent source of bug reports, so would be good to fix it in a "micro" way if possible.

First thing here would be to get CI to pass on this PR. It looks like tests/float/string_format_modulo2_intbig.py is failing.

One advantage of any float32 format conversion is it's possible to exhaustively test every single combination of bits (there's only 4 billion of them) in just a few hours.

Did you do such testing on this new code?

@goatchurchprime
Copy link
Author

@dpgeorge I can compile+run C in the jupyter notebook, which could make development slightly more brisk.

A quick time trial with the C-code printf(%f) and atof() indicates that all 4billion floats could be scanned in under an hour, like this: https://github.com/goatchurchprime/jupyter_micropython_developer_notebooks/blob/master/projects/float32_conversions/C-code_experiments.ipynb

Would it be more useful to work on this self-contained like @dhylands code so it works outside of Micropython, but so it can can then be copied in if it's good enough?

I can extract a series of decimal digits using int multiplication by 10 only in the lower bytes of a word, and slicing off the top byte for each decimal digit, so we won't have so many float operations happening.

A couple more things:

  • I need a hint about what these integration errors are (nothing jumps out at me when I click through those links)

  • Is float64/double needed, or is it not common on micropython? (Obviously exhaustive testing is not possible with that type.)

tannewt pushed a commit to tannewt/circuitpython that referenced this pull request Dec 29, 2021
@dpgeorge
Copy link
Member

Running this patch on latest master, the tests/float/string_format_modulo2_intbig.py test fails. One of the tests generates a formatted float of the form 0./,),(-*,(.0000000000000000001. That would need to be fixed.

@dpwe
Copy link
Contributor

dpwe commented Jul 6, 2022

I have an independently-developed fix for this issue (poor rounding when printing floats) that passes all the "make tests" except math_fun_special, where it prints 3.6288e+05 for math.gamma(10), whereas the previous implementation printed 3.629e+05. Since the format specification is {:.4g}, I think my implementation is actually more correct there.

It's a bit hacky, in that it special cases numbers in the (abs) range 1e1..1e10 and falls back to the existing routine otherwise. I couldn't get it to work well for very large numbers (the rounding bites me in a different way), but the point is to have exact representation of integers where the float actually stores them exactly.

Is this worth putting into a pull request?

@dpwe
Copy link
Contributor

dpwe commented Jul 6, 2022

Oh oops I misunderstood the 4 in {:.4g} as decimal digits, not significant figures. Will keep fixing...

@dpwe
Copy link
Contributor

dpwe commented Jul 6, 2022

See #8878. Now all original tests pass, and I added some new tests for number formatting.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
py-core Relates to py/ directory in source
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants