1

I want to add/subtract for any float some smallest values which will change this float value about one bit of mantissa/significant part. How to calculate such small number efficiently.

For example I have such array of x:

xs = [1e300, 1e0, 1e-300]

What will be function for it to generate the smallest value? All assertion should be valid.

for x in xs:
  assert x < x + smallestChange(x)
  assert x > x - smallestChange(x)

Consider that 1e308 + 1 == 1e308 since 1 does means 0 for mantissa so `smallestChange' should be dynamic.

Pure Python solution will be the best.


Why this is not duplicate of Increment a python floating point value by the smallest possible amount - two simple tests prove it with invalid results.

(1) The question is not aswered in Increment a python floating point value by the smallest possible amount difference:

Increment a python floating point value by the smallest possible amount just not works try this code:

import math
epsilon  = math.ldexp(1.0, -53) # smallest double that 0.5+epsilon != 0.5
maxDouble = float(2**1024 - 2**971)  # From the IEEE 754 standard
minDouble  = math.ldexp(1.0, -1022) # min positive normalized double
smallEpsilon  = math.ldexp(1.0, -1074) # smallest increment for doubles < minFloat
infinity = math.ldexp(1.0, 1023) * 2

def nextafter(x,y):    
    """returns the next IEEE double after x in the direction of y if possible"""
    if y==x:
       return y         #if x==y, no increment

    # handle NaN
    if x!=x or y!=y:
        return x + y       

    if x >= infinity:
        return infinity

    if x <= -infinity:
        return -infinity

    if -minDouble < x < minDouble:
        if y > x:
            return x + smallEpsilon
        else:
            return x - smallEpsilon  

    m, e = math.frexp(x)        
    if y > x:
        m += epsilon
    else:
        m -= epsilon

    return math.ldexp(m,e)  
print nextafter(1e307, 1e308), 'nextafter(1e307, 1e308)'
print nextafter(1e308, 1e307), 'nextafter(1e308, 1e307)'

Results of [Increment a python floating point value by the smallest possible amount] is invalid:

1e+307 nextafter(1e307, 1e308) # invalid 2e307 is possible!!!
1e+308 nextafter(1e308, 1e307) # invalid 9e307 is possible!!!

(2) It was not asked how to add/substract the smallest value but was asked how to add/substract value in specific direction - propose solution is need to know x and y. Here is required to know only x.

(3) Propose solution in Increment a python floating point value by the smallest possible amount will not work on border conditions.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Chameleon
  • 9,722
  • 16
  • 65
  • 127
  • So, for given float in IEEE 754 notation, you'd want a float with the same sign and exponent, but fraction equal to 1 (the lowest bit 1, rest 0), right?. – Maciej Gol Nov 27 '13 at 16:14
  • @kroolik Yes for float in Python. Not sure let me explain: I want to add or subtract small piece, so this will be the lowest bit sometimes (it will require to handle overflow or underflow as normally). Is it clear now for you? – Chameleon Nov 27 '13 at 16:18
  • Saying simple it need to get next the less greater number or next the high lesser number - so by analogy of integers for 1 is 2 and 0. – Chameleon Nov 27 '13 at 16:22
  • It *is* a duplicate of that issue. Just read Pyson's explanation. He explicitly warns that the python code that you cite is not fully QA' and might not handle all edge case correctly. You should one of the other solutions which he recommends, which rely on a proven tested implementation of nextafter – oefe Nov 27 '13 at 19:38
  • @oefe You are inaccurate read carefully I explained that this not duplicate of **exactly that answer because I prove that is not working/has bug**. You should test it if you not believe - you will get same errors fro what you propose. – Chameleon Nov 27 '13 at 19:39
  • @oefe I **tested it** it is not working. As I explain to you **second time** it not duplicate and **pure Python** code from this answer is not working by design and should not work `epsilon` value is invalid. Not want numpy or binary tricks since will not work in my environment. – Chameleon Nov 27 '13 at 19:53
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/42063/discussion-between-oefe-and-chameleon) – oefe Nov 27 '13 at 19:57
  • @ofer *Ok, it is even worse ...* - read what is at the end from StakOverflow - if question is not duplicate ask the new question with explanation why this is not duplicate. I tested your link and **it is not working by design** and not able to fix - it is also solution of different thing :) – Chameleon Nov 27 '13 at 19:59
  • 2
    Check http://stackoverflow.com/questions/10420848/how-do-you-get-the-next-value-in-the-floating-point-sequence – Maciej Gol Nov 27 '13 at 20:11
  • I will check if is it useful today or tomorrow thanks for suggestion - look good ... - I know some solution with hex but want do something faster. – Chameleon Nov 27 '13 at 20:23
  • @CL. Is it Duplicate of what - you not specified? – Chameleon Nov 27 '13 at 23:05
  • Your 'bug' is the way you are printing the result of `nextafter` Try `print '{:30.20}'.format(nextafter(1e307, 1e308))` The Python default print format can obscure decimal places that are relevant in your example. Cheers –  Jan 19 '15 at 02:12

0 Answers0