Implementing single-precision division as double-precision multiplication

后端 未结 3 1009
礼貌的吻别
礼貌的吻别 2020-12-19 20:29

Question

For a C99 compiler implementing exact IEEE 754 arithmetic, do values of f, divisor of type float exist such that

相关标签:
3条回答
  • 2020-12-19 21:09

    Random search resulted in an example.

    Looks like when the result is a "denormal/subnormal" number, the inequality is possible. But then, maybe my platform is not IEEE 754 compliant?

    f        0x1.7cbff8p-25 
    divisor -0x1.839p+116
    q       -0x1.f8p-142
    q2      -0x1.f6p-142
    
    int MyIsFinite(float f) {
      union {
        float f;
        unsigned char uc[sizeof (float)];
        unsigned long ul;
      } x;
      x.f = f;
      return (x.ul & 0x7F800000L) != 0x7F800000L;
    }
    
    float floatRandom() {
      union {
        float f;
        unsigned char uc[sizeof (float)];
      } x;
      do {
        size_t i;
        for (i=0; i<sizeof(x.uc); i++) x.uc[i] = rand();
      } while (!MyIsFinite(x.f));
      return x.f;
    }
    
    void testPC() {
      for (;;) {
        volatile float f, divisor, q, qd;
        do {
          f = floatRandom();
          divisor = floatRandom();
          q = f / divisor;
        } while (!MyIsFinite(q));
        qd = (float) (f * (1.0 / divisor));
        if (qd != q) {
          printf("%a %a %a %a\n", f, divisor, q, qd);
          return;
        }
      }
    
    }
    

    Eclipse PC Version: Juno Service Release 2 Build id: 20130225-0426

    0 讨论(0)
  • 2020-12-19 21:22

    Your program won't print anything, assuming round-ties-to-even rounding mode. The essence of the argument is as follows:

    We're assuming that both f and divisor are between 1.0 and 2.0. So f = a / 2^23 and divisor = b / 2^23 for some integers a and b in the range [2^23, 2^24). The case divisor = 1.0 isn't interesting, so we can further assume that b > 2^23.

    The only way that (float)(f * (1.0 / divisor)) could give the wrong result would be for the exact value f / divisor to be so close to a halfway case (i.e., a number exactly halfway between two single-precision floats) that the accumulated errors in the expression f * (1.0 / divisor) push us to the other side of that halfway case from the true value.

    But that can't happen. For simplicity, let's first assume that f >= divisor, so that the exact quotient is in [1.0, 2.0). Now any halfway case for single precision in the interval [1.0, 2.0) has the form c / 2^24 for some odd integer c with 2^24 < c < 2^25. The exact value of f / divisor is a / b, so the absolute value of the difference f / divisor - c / 2^24 is bounded below by 1 / (2^24 b), so is at least 1 / 2^48 (since b < 2^24). So we're more than 16 double-precision ulps away from any halfway case, and it should be easy to show that the error in the double precision computation can never exceed 16 ulps. (I haven't done the arithmetic, but I'd guess it's easy to show an upper bound of 3 ulps on the error.)

    So f / divisor can't be close enough to a halfway case to create problems. Note that f / divisor can't be an exact halfway case, either: since c is odd, c and 2^24 are relatively prime, so the only way we could have c / 2^24 = a / b is if b is a multiple of 2^24. But b is in the range (2^23, 2^24), so that's not possible.

    The case where f < divisor is similar: the halfway cases then have the form c / 2^25 and the analogous argument shows that abs(f / divisor - c / 2^25) is greater than 1 / 2^49, which again gives us a margin of 16 double-precision ulps to play with.

    0 讨论(0)
  • 2020-12-19 21:27

    It's certainly not possible if non-default rounding modes are possible. For example, in replacing 3.0f / 3.0f with 3.0f * C, a value of C less than the exact reciprocal would yield the wrong result in downward or toward-zero rounding modes, whereas a value of C greater than the exact reciprocal would yield the wrong result for upward rounding mode.

    It's less clear to me whether what you're looking for is possible if you restrict to default rounding mode. I'll think about it and revise this answer if I come up with anything.

    0 讨论(0)
提交回复
热议问题