See https://tech.ebayinc.com/engineering/fast-approximate-logarithms-part-iii-the-formulas/
| 63 | |
| 64 | // See https://tech.ebayinc.com/engineering/fast-approximate-logarithms-part-iii-the-formulas/ |
| 65 | inline vfloat spmd_kernel::log2_est(vfloat v) |
| 66 | { |
| 67 | vfloat signif, fexp; |
| 68 | |
| 69 | // Just clamp to a very small value, instead of checking for invalid inputs. |
| 70 | vfloat x = max(v, 2.2e-38f); |
| 71 | |
| 72 | /* |
| 73 | * Assume IEEE representation, which is sgn(1):exp(8):frac(23) |
| 74 | * representing (1+frac)*2^(exp-127). Call 1+frac the significand |
| 75 | */ |
| 76 | |
| 77 | // get exponent |
| 78 | vint ux1_i = cast_vfloat_to_vint(x); |
| 79 | |
| 80 | vint exp = VUINT_SHIFT_RIGHT(ux1_i & 0x7F800000, 23); |
| 81 | |
| 82 | // actual exponent is exp-127, will subtract 127 later |
| 83 | |
| 84 | vint ux2_i; |
| 85 | vfloat ux2_f; |
| 86 | |
| 87 | vint greater = ux1_i & 0x00400000; // true if signif > 1.5 |
| 88 | SPMD_SIF(greater != 0) |
| 89 | { |
| 90 | // signif >= 1.5 so need to divide by 2. Accomplish this by stuffing exp = 126 which corresponds to an exponent of -1 |
| 91 | store_all(ux2_i, (ux1_i & 0x007FFFFF) | 0x3f000000); |
| 92 | |
| 93 | store_all(ux2_f, cast_vint_to_vfloat(ux2_i)); |
| 94 | |
| 95 | // 126 instead of 127 compensates for division by 2 |
| 96 | store_all(fexp, vfloat(exp - 126)); |
| 97 | } |
| 98 | SPMD_SELSE(greater != 0) |
| 99 | { |
| 100 | // get signif by stuffing exp = 127 which corresponds to an exponent of 0 |
| 101 | store(ux2_i, (ux1_i & 0x007FFFFF) | 0x3f800000); |
| 102 | |
| 103 | store(ux2_f, cast_vint_to_vfloat(ux2_i)); |
| 104 | |
| 105 | store(fexp, vfloat(exp - 127)); |
| 106 | } |
| 107 | SPMD_SENDIF |
| 108 | |
| 109 | store_all(signif, ux2_f); |
| 110 | store_all(signif, signif - 1.0f); |
| 111 | |
| 112 | const float a = 0.1501692f, b = 3.4226132f, c = 5.0225057f, d = 4.1130283f, e = 3.4813372f; |
| 113 | |
| 114 | vfloat xm1 = signif; |
| 115 | vfloat xm1sqr = xm1 * xm1; |
| 116 | |
| 117 | return fexp + ((a * (xm1sqr * xm1) + b * xm1sqr + c * xm1) / (xm1sqr + d * xm1 + e)); |
| 118 | |
| 119 | // fma lowers accuracy for SSE4.1 - no idea why (compiler reordering?) |
| 120 | //return fexp + ((vfma(a, (xm1sqr * xm1), vfma(b, xm1sqr, c * xm1))) / (xm1sqr + vfma(d, xm1, e))); |
| 121 | } |
| 122 |
nothing calls this directly
no test coverage detected