tag:blogger.com,1999:blog-5246987755651065286.post3582155940205083886..comments2024-02-22T16:15:42.388-08:00Comments on cbloom rants: 01-17-09 - Float to Intcbloomhttp://www.blogger.com/profile/10714564834899413045noreply@blogger.comBlogger4125tag:blogger.com,1999:blog-5246987755651065286.post-79809974590561448862010-08-13T06:42:51.692-07:002010-08-13T06:42:51.692-07:00Touché, you are right. Since ftoi_floor takes a d...Touché, you are right. Since ftoi_floor takes a double I figured you wanted full range support. I may not have read the post thoroughly enough. Although, if this is running on x86 hardware you should probably use long double, if your compiler supports 80bit floats, otherwise every operation must make a round trip to memory for truncation. Something we see with GCC's optimizer, is that all float math is internally in 80bit floats, so all intermediate math must use the 80bit version of magic or use -mfpmath=sse and the correct magic for each type, fun times.<br /><br />I mainly came about the problem of doing rounding (every kind) in SSE with full range support for each type, and have learned more than I even wanted to. Magic has to be the reverse sign or bad rounding occurs in the range of [magic/3, magic*4/3], plus overflow in the range of [maxval - magic, maxval]. Sigh, modulus with euclidean division, wrapping, and mirroring where cake after figuring all this out.<br /><br />My attempt:<br /><br />// should be a constant or result in a constant and an fscale instruction<br />long double magic(int precision) { return (1.5 * std::pow((long double)2, std::numeric_limits::digits - 2)) * std::pow((long double)2, -precision); }<br /><br />// the sse version of this ((test & -0.0) ^ value)<br />FloatType toggleSign(FloatType value, FloatType test) { return test < 0 ? -value : value); }<br /><br />FloatType roundToEven(FloatType value, FloatType magic)<br />{<br />magic = toggleSign(magic * 2, value);<br />return (value - magic) + magic;<br />}<br /><br />FloatType roundDirect(FloatType value, FloatType magic, bool roundUp, bool roundAtHalf, bool asymetric)<br />{<br />FloatType quarter = 0.25;<br />quarter = asymetric ? quarter : thatType::toggleSign(quarter, value);<br />magic = asymetric ? magic : thatType::toggleSign(magic, value);<br />value = (roundUp ? value + quarter : value - quarter) - magic;<br />return (roundUp ^ roundAtHalf ? value + quarter : value - quarter) + magic;<br />}<br /><br />FloatType ceil(FloatType value) { return roundDirect(value, magic(0), true, false, true); }<br />FloatType floor(FloatType value) { return roundDirect(value, magic(0), false, false, true); }<br />FloatType trunc(FloatType value) { return roundDirect(value, magic(0), false, false, false); }<br />FloatType rndUp(FloatType value) { return roundDirect(value, magic(0), true, true, true); }<br />FloatType rndDn(FloatType value) { return roundDirect(value, magic(0), false, true, true); }<br />FloatType rndAway(FloatType value) { return roundDirect(value, magic(0), true, true, false); }<br />FloatType rndTo0(FloatType value) { return roundDirect(value, magic(0), false, true, false); }<br /><br />Ok that was way more than I should have wrote, but maybe it will save someone else from my pain.Anonymoushttps://www.blogger.com/profile/01599561685614570777noreply@blogger.comtag:blogger.com,1999:blog-5246987755651065286.post-39541974122042656132010-08-12T15:57:56.901-07:002010-08-12T15:57:56.901-07:00Sigh sigh sigh la la la
This only works on single...Sigh sigh sigh la la la<br /><br />This only works on single precision *floats* . The closest number to 1.0 that you can have in float is<br /><br />0.99999988<br /><br />and it works just finecbloomhttps://www.blogger.com/profile/10714564834899413045noreply@blogger.comtag:blogger.com,1999:blog-5246987755651065286.post-72226955936351344382010-08-12T14:57:27.863-07:002010-08-12T14:57:27.863-07:00Has noone ever noticed that it doesn't work.
...Has noone ever noticed that it doesn't work.<br /><br />Try floor 0.9999999999999990008<br /> sub doublemagicroundeps<br />0.50000001499999902066 <br /> add floatutil_xs_doublemagic<br />6755399441055745<br /> in binary<br />0100001100111000000000000000000000000000000000000000000000000001<br /> keep lower bits<br />1 (WRONG)<br /><br />The correct floor 0.9999999999999990008<br /> sub 0.25<br />0.7499999999999990008 <br /> add floatutil_xs_doublemagic / 2<br />3377699720527872.5 <br /> in binary<br />0100001100101000000000000000000000000000000000000000000000000001<br /> put lower bits in int<br />1<br /> shift right 1<br />0 (correct)<br /><br />One More Time<br /><br />Try floor 1.9999999999999988898<br /> sub doublemagicroundeps<br />1.5000000149999990207<br /> add floatutil_xs_doublemagic<br />6755399441055746<br /> in binary<br />0100001100111000000000000000000000000000000000000000000000000010<br /> keep lower bits<br />2 (WRONG)<br /><br />The correct floor 1.9999999999999988898 <br /> sub 0.25<br />1.7499999999999988898 <br /> add floatutil_xs_doublemagic / 2<br />3377699720527873.5 <br /> in binary<br />0100001100101000000000000000000000000000000000000000000000000011<br /> put lower bits in int<br />2<br /> shift right 1<br />1 (correct)Anonymoushttps://www.blogger.com/profile/01599561685614570777noreply@blogger.comtag:blogger.com,1999:blog-5246987755651065286.post-45021277194797837622009-01-18T23:45:00.000-08:002009-01-18T23:45:00.000-08:00I assume this whole thing has been invented multip...I assume this whole thing has been invented multiple times, but it's nice to see that Herf's stereopsis articles references Hecker's article which cites me for the '1.5' in the magic number. Yay me.<BR/><BR/>(I remember figuring that out and posting it to a mailing list he and I and Terje were on back when I was at Looking Glass, but I can't actually nail down precisely when it was.)Anonymousnoreply@blogger.com