How does this float square root approximation work?

前端 未结 4 1024
终归单人心
终归单人心 2020-12-24 01:54

I found a rather strange but working square root approximation for floats; I really don\'t get it. Can someone explain me why this code works?

f         


        
4条回答
  •  情书的邮戳
    2020-12-24 02:35

    Adding a wiki test harness to test all float.

    The approximation is within 4% for many float, but very poor for sub-normal numbers. YMMV

    Worst:1.401298e-45 211749.20%
    Average:0.63%
    Worst:1.262738e-38 3.52%
    Average:0.02%
    

    Note that with argument of +/-0.0, the result is not zero.

    printf("% e % e\n", sqrtf(+0.0), sqrt_apx(0.0));  //  0.000000e+00  7.930346e-20
    printf("% e % e\n", sqrtf(-0.0), sqrt_apx(-0.0)); // -0.000000e+00 -2.698557e+19
    

    Test code

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    float sqrt_apx(float f) {
      const int result = 0x1fbb4000 + (*(int*) &f >> 1);
      return *(float*) &result;
    }
    
    double error_value = 0.0;
    double error_worst = 0.0;
    double error_sum = 0.0;
    unsigned long error_count = 0;
    
    void sqrt_test(float f) {
      if (f == 0) return;
      volatile float y0 = sqrtf(f);
      volatile float y1 = sqrt_apx(f);
      double error = (1.0 * y1 - y0) / y0;
      error = fabs(error);
      if (error > error_worst) {
        error_worst = error;
        error_value = f;
      }
      error_sum += error;
      error_count++;
    }
    
    void sqrt_tests(float f0, float f1) {
      error_value = error_worst = error_sum = 0.0;
      error_count = 0;
      for (;;) {
        sqrt_test(f0);
        if (f0 == f1) break;
        f0 = nextafterf(f0, f1);
      }
      printf("Worst:%e %.2f%%\n", error_value, error_worst*100.0);
      printf("Average:%.2f%%\n", error_sum / error_count);
      fflush(stdout);
    }
    
    int main() {
      sqrt_tests(FLT_TRUE_MIN, FLT_MIN);
      sqrt_tests(FLT_MIN, FLT_MAX);
      return 0;
    }
    

提交回复
热议问题