Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>One way to get at your question is to find the size of an <em>ULP</em>, or <strong>U</strong>nit in the <strong>L</strong>ast <strong>P</strong>lace, of your floating-point number. Simplifying a little bit, this is the distance between a given floating-point number and the next larger number. Again, simplifying a little bit, given a representable floating-point value x, any decimal string whose value is between (x - 1/2 ulp) and (x + 1/2 ulp) will be rounded to x when converted to a floating-point value.</p> <p>The trick is that (x +/- 1/2 ulp) is not a representable floating-point number, so actually calculating its value requires that you use a wider floating-point type (if one is available) or an arbitrary width big decimal or similar type to do the computation.</p> <p>How do you find the size of an ulp? One relatively easy way is roughly what you suggested, written here is C-ish pseudocode because I don't know C#:</p> <pre><code>float absX = absoluteValue(x); uint32_t bitPattern = getRepresentationOfFloat(absx); bitPattern++; float nextFloatNumber = getFloatFromRepresentation(bitPattern); float ulpOfX = (nextFloatNumber - absX); </code></pre> <p>This works because adding one to the bit pattern of x exactly corresponds to adding one ulp to the value of x. No floating-point rounding occurs in the subtraction because the values involved are so close (in particular, there is a theorem of ieee-754 floating-point arithmetic that if two numbers x and y satisfy y/2 &lt;= x &lt;= 2y, then <code>x - y</code> is computed exactly). The only caveats here are:</p> <ol> <li>if x happens to be the largest finite floating point number, this won't work (it will return <code>inf</code>, which is clearly wrong).</li> <li>if your platform does not correctly support gradual underflow (say an embedded device running in flush-to-zero mode), this won't work for very small values of x.</li> </ol> <p>It sounds like you're not likely to be in either of those situations, so this should work just fine for your purposes.</p> <p>Now that you know what an ulp of x is, you can find the interval of values that rounds to x. You can compute ulp(x)/2 exactly in floating-point, because floating-point division by 2 is exact (again, barring underflow). Then you need only compute the value of x +/- ulp(x)/2 suitable larger floating-point type (<code>double</code> will work if you're interested in <code>float</code>) or in a Big Decimal type, and you have your interval.</p> <p>I made a few simplifying assumptions through this explanation. If you need this to really be spelled out exactly, leave a comment and I'll expand on the sections that are a bit fuzzy when I get the chance.</p> <hr> <p><strong>One other note</strong> the following statement in your question:</p> <blockquote> <p>In the case of 0.1, there is no lower decimal number that is represented with the same bit pattern</p> </blockquote> <p>is incorrect. You just happened to be looking at the wrong values (0.999999... instead of 0.099999... -- an easy typo to make).</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload