5 ms·
the posit standard has a NaR value that does everything I wish NaN and Inf were in ieee it is the result of 1/0, and sqrt(-1) etc. there is only one of them an
by adgjlsfhk1 4y ago
the posit standard has a NaR value that does everything I wish NaN and Inf were in ieee it is the result of 1/0, and sqrt(-1) etc. there is only one of them and it compares equal with itself and is defined as less than all other posits. Real numbers have a total order so it's silly that floating point doesn't. Furthermore the Posit ordering operations (bitwise) are the same as the signed integer ones which makes your processor simpler and makes it easier to do things like write radix sorts for floats.
> You are confusing == for floats with == for bit patterns
The problem is that == for floats doesn't behave like an equality operation. x==x doesn't hold (reflexivity) and x==y => f(x)==f(y) doesn't hold. These are The two most important parts of what equality means.
To take your example of sqrt(xx), for Float16, of the 65k values, 34k give exact answers (counting NaNs as exact otherwise subtract 2k), 16k overflow and 5k underflow. There are also 9k inexact answers of which 6k are within 2 ULPs, and the others are further off (since xx loses precision due to subnormals). so in other words you get exact answers 1/2 of the time and close answers 60% of the time. With Posit16, you get 47k exact answers, and 18k inexact answers. How inexact are these inexact answers? 15k are within 2 ULP and only 2.9k aren't. (Of the 2.9k that aren't, Float16 would have overflowed or underflowed in all but 278 of the cases and these 278 cases are all accurate to less than 4 ULPs).
Posits do lose the ability to do error free transforms, but IMO for 32 bit and smaller math, this isn't a major loss as if you want more accuracy you can use more bits and it will usually be faster than the error free transform.
- adgjlsfhk1 4y agoI've done a similar experiment with log1p(expm1(x)) and for that FLoat16 has 35k exact, 26k overflow, 1.3k within 4 ULP and 3k with more than 4 ULP error. Posits for comparison are 38k exact, 19k within 4 ULP, and 8k more than 4 ULP.
- SideQuark 4y ago>To take your example of sqrt(xx), Yes, for small floats posits do ok, but they fail for other sizes. For example, here's float32 vs posit32 for 100,000 random values in ranges 1e2,1e4,..,1e18. Posit32 fails on (respectively) 21%, 71%, 91%, 97%, 99%, 99.9%, 99.97%, 99.99% of the cases. Float32 fails on 0 of them. Julia code at the bottom. Posit even fails on simple integer multiplication so often that you'd be terribly pressed to know ahead of time when it happens. For example, take integers 1 to 40 for i and j, multiple as posit16 and as float16, an see how they do. Posit fails 1.75% of the values, float fails none. This is simple multiplication of numbers well within range. The same problem happens in posit32,64,anysize, but not for the same sized floats. >These are The two most important parts of what equality means. As a PhD in math, this is not what equality means. You'll find nothing like that here for example https://en.wikipedia.org/wiki/Equality_(mathematics) https://en.wikipedia.org/wiki/Equality_(mathematics) And if you're worried about equality, you might notice that in posit16, 2739 gives 1052 instead of 1053, which is real (in)equality. You worry so much about made up concerns that you miss the crazy bad results scattered throughout posits. Posits of all sizes make errors when multiplying by powers of two that floats do not make (die to their inability to keep digits). For example, in posit8, 2.01.03125 returns 2.0, 102 returns 16, and examples this bad can be found for any size posit. To see this, take 1e6 random values in 0-100, mult by 2, then divide by 2, and see how many made it round trip. All float16 values do. 4% of posit16 values do not round trip. These are small numbers - the entire computation stays in the range 0-200, and this is even the base of the underlying number. Posit32 has the same failure rate for the same reason: posits lose precision even under small multiplications. As a result, posits fail at x-y=0 means x=y, which is also pretty fundamental, is it not? Want to compute a discriminant sqrt(bb-4ac)? Good luck, nearby values for a,b,c don't give smooth results, and routinely give imaginary numbers when they should be real (due to the above screwiness around powers of 2). There's so many failure cases, not even at the edge of the ranges, where posits fail and equivalent sized floats don't, that doing any simple computations is error prone. Here's the Julia code for the sqrt failures. You can do similar error checks for a ton of computations and you'll find posits failing a significant amount of them. # count failures of float32 and Posit32 in Julia # for sqrt(x*x) ==?= x using Random Random.seed!(1234) # make reproducible scale = 1.0f0 # try exponent 4,6,8,10,etc for s in 1:9 # powers 2,4,5,8,10,...18 scale *= 100.0f0 badF,goodF = 0,0 badP,goodP = 0,0 for i in 1:10000 f = rand()*scale f1::Float32 = f f2 = f1*f1 f3 = sqrt(f2) @assert typeof(f1) == Float32 @assert typeof(f2) == Float32 @assert typeof(f3) == Float32 p1 = Posit32(f) p2 = p1*p1 p3 = sqrt(p2) @assert typeof(p1) == Posit32 @assert typeof(p2) == Posit32 @assert typeof(p3) == Posit32 if f1 != f3 badF+=1 else goodF+=1 end if p1 != p3 badP+=1 else goodP+=1 end end println("Scaling: $(scale)") println("float: $(goodF) good, $(badF) bad, $(100*badF/(goodF+badF)) % failed") println("posit: $(goodP) good, $(badP) bad, $(100*badP/(goodP+badP)) % failed")
- Dylan16807 4y ago> Posit32 fails on (respectively) 21%, 71%, 91%, 97%, 99%, 99.9%, 99.97%, 99.99% of the cases. Float32 fails on 0 of them. Julia code at the bottom. A lot of those are only losing a bit or two of precision, though, and many of them are happening in a region where posit32 has more bits of precision than float32 to start with. I'm not very fond of having only 2 exponent bits on the standard posit32. It makes the region with significant precision loss a lot bigger. But if you give a posit exactly two fewer exponent bits than a float, it shouldn't do worse than that float by more than one bit anywhere. I think that would be a better apples-to-apples comparison. Standard posit32 is tuned much more toward having bonus precision near 1.0, and other tests would show it beating float32 for many tasks. > Posit even fails on simple integer multiplication so often that you'd be terribly pressed to know ahead of time when it happens. For example, take integers 1 to 40 for i and j, multiple as posit16 and as float16, an see how they do. Posit fails 1.75% of the values, float fails none. Posit16 starts failing to represent odd numbers at 1024. Float16 starts failing to represent odd numbers at 2048. Not ideal but not a big issue. 1052 vs. 1053 is definitely not a "crazy bad problem"! And on the other hand, consider multiplying numbers from 1 to 400. Around the high end of the results, posit16 will store numbers below 65k with 8 bits of mantissa, and numbers above 65k with 7 bits of mantissa. Float16 will store numbers below 65k with 10 bits of mantissa, and everything above 65k becomes infinity. > Posits of all sizes make errors when multiplying by powers of two that floats do not make (die to their inability to keep digits). For example, in posit8, 2.0 * 1.03125 returns 2.0, 10 * 2 returns 16, and examples this bad can be found for any size posit. What's your chosen IEEE competitor? The example on wikipedia has 3 bits of mantissa. It also says 2.0 * 33/32 == 2.0 And while that format can represent 20, it only has a third of the dynamic range. Tradeoffs. No 8 bit format is going to be good. What kind of float would pass the 1.03125 test, anyway? You'd need 5 bits of mantissa to represent that. In an 8 bit float, that means you have a... 2 bit exponent? No, that would be ridiculous, it would have to be a 3 bit exponent with no sign bit? That would imply the smallest normal value is 1/4 and the largest value is 15.75 If we face that against an 8 bit unsigned posit with es=1, then it would have 5 bits of mantissa in [1/4, 4), 4 bits of mantissa in [4, 16), and 3 bits of mantissa in [16, 64). That means this posit would be able to represent both 2.0 * 1.03125 and 20, and it would have four times as much as dynamic range. I wasn't expecting such a blowout until I started doing the math. Wow, congrats posit. > To see this, take 1e6 random values in 0-100, mult by 2, then divide by 2, and see how many made it round trip. All float16 values do. 4% of posit16 values do not round trip. These are small numbers - the entire computation stays in the range 0-200, and this is even the base of the underlying number. Posit32 has the same failure rate for the same reason: posits lose precision even under small multiplications. Yes, they lose one bit of precision if you cross certain thresholds. That is a cost to keep in mind. But look at which values fail to round-trip. It should mostly be numbers between 8 and 16, I think? Those numbers started with 11 bits of mantissa, and they were reduced to 10. Float16 is always 10. This is not a problem. For posit32 it's even more stark. Those numbers start with 27 bits of mantissa, and get reduced to 26 bits. Float32 is always 23. > As a result, posits fail at x-y=0 means x=y, which is also pretty fundamental, is it not? I don't think that would happen. Do you have an example number? What can happen is that k*x - k*y=0 even though x!=y. With normal floating point that can't happen when k is a power of 2, but it can happen with lots of values of k. 4/3 * 3 - 4/3 * 3.0000000000000004 = 0, with normal floating point. In fact every third pair of adjacent floats incorrectly returns 0.