Skip to content

math: powf: make a precision vs size trade-off for flash-constrained builds #3245

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
wants to merge 1 commit into from

Conversation

jepler
Copy link

@jepler jepler commented Aug 5, 2020

.. by calculating x**y as exp(y*log(x)) after some suitable initial tests.

Size savings is 1352 bytes on Trinket M0, and the existing more accurate behavior is preserved on boards with CIRCUITPY_FULL_BUILD.

The most notable anomaly I found is that powf() is used in number parsing and it changes from the correct

>>> float("10000000") - float("1e7")
0.0  # i.e., they are equal

to the incorrect

>>> float(10000000) - float("1e7")
4.0 # i.e., they are unequal in the 7th digit

I investigated whether "exponentiation by squaring" gave more accurate results for integer exponents, but it did not.

New behavior:

>>> sum( (-1.1) ** x for x in range(-6, 6))
-0.574803
>>> sum( 10. ** y for y in range(-6, 6))
111111.0
>>> sum( y ** (4/3) for y in range(-6, 6) )  # Complex values not supported
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <genexpr>
ValueError: complex values not supported
>>> sum( y ** (-4/3) for y in range(1, 6) )
1.90242

Original behavior:

>>> sum( (-1.1) ** x for x in range(-6, 6))
-0.574803
>>> sum( 10. ** y for y in range(-6, 6))
111111.0
>>> sum( y ** (4/3) for y in range(-6, 6) )  # Complex values not supported
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <genexpr>
ValueError: complex values not supported
>>> sum( y ** (-4/3) for y in range(1, 6) )
1.90242

Desktop Python behavior:

>>> sum( (-1.1) ** x for x in range(-6, 6))
-0.574803366641059
>>> sum( 10. ** y for y in range(-6, 6))
111111.111111
>>> sum( y ** (4./3) for y in range(-6, 6) )  # Complex values not supported
(5.921675597487694-29.140714142379153j)
>>> sum( y ** (-4./3) for y in range(1, 6) )
1.9024215285409685

@jepler
Copy link
Author

jepler commented Aug 5, 2020

I made this a separate PR because making a function less accurate is more debatable than everything in the other PR

@dhalbert dhalbert mentioned this pull request Aug 5, 2020
…builds

.. by calculating x**y as exp(y*log(x)) after some suitable initial
tests.

The most notable anomaly I found is that powf() is used in number parsing
and it changes from the correct
    >>> float("10000000") - float("1e7")
    0.0
to the incorrect
    >>> float(10000000) - float("1e7")
    4.0

Size savings is 1352 bytes on Trinket M0, and the existing more accurate
behavior is preserved on boards with CIRCUITPY_FULL_BUILD.

I investigated whether "exponentiation by squaring" gave more accurate results
for integer exponents, but it did not.

New behavior:
```
>>> sum( (-1.1) ** x for x in range(-6, 6))
-0.574803
>>> sum( 10. ** y for y in range(-6, 6))
111111.0
>>> sum( y ** (4/3) for y in range(-6, 6) )  # Complex values not supported
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <genexpr>
ValueError: complex values not supported
>>> sum( y ** (-4/3) for y in range(1, 6) )
1.90242
```

Original behavior:
```
>>> sum( (-1.1) ** x for x in range(-6, 6))
-0.574803
>>> sum( 10. ** y for y in range(-6, 6))
111111.0
>>> sum( y ** (4/3) for y in range(-6, 6) )  # Complex values not supported
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <genexpr>
ValueError: complex values not supported
>>> sum( y ** (-4/3) for y in range(1, 6) )
1.90242
```

Desktop Python behavior:
```
>>> sum( (-1.1) ** x for x in range(-6, 6))
-0.574803366641059
>>> sum( 10. ** y for y in range(-6, 6))
111111.111111
>>> sum( y ** (4./3) for y in range(-6, 6) )  # Complex values not supported
(5.921675597487694-29.140714142379153j)
>>> sum( y ** (-4./3) for y in range(1, 6) )
1.9024215285409685
```
@jepler jepler force-pushed the powf-inaccurate-smaller branch from 48ca9f3 to 484fcf9 Compare August 7, 2020 15:15
@jepler
Copy link
Author

jepler commented Aug 7, 2020

Rebased and force-pushed because this was still showing commits from 3236 even though that PR was merged.

dhalbert
dhalbert previously approved these changes Aug 15, 2020
Copy link
Collaborator

@dhalbert dhalbert left a comment

Choose a reason for hiding this comment

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

In the original post, are the "New behavior" and "Original behavior" results supposed to be different? They look the same, to me, but maybe I'm missing something.

I would be reluctant to change the behavior of number parsing across different boards, since it may affect various programs. So I'm not sure this is worth the savings, sadly.

@dhalbert dhalbert dismissed their stale review August 15, 2020 19:17

checked wrong box

@jepler
Copy link
Author

jepler commented Aug 15, 2020

The original and new behavior are close enough over those arbitrary tests I did that the numbers print the same. However, there are differences, as evidenced by the changed parsing of the value float(1e7)

I agree with your unease and so you should feel free to close this up, but I may dredge it up again the next time we face space pressure on M0. I'm not sure how soon that will happen again.

@dhalbert
Copy link
Collaborator

OK, I'll close this for now, but we'll keep it in one of our numerous back pockets.

@dhalbert dhalbert closed this Aug 17, 2020
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.

2 participants