Merged
float类型接口性能优化 #6308
float类型接口性能优化 #6308
Merged
xuyiyangAdd on Sep 21
Total: 1 files changed+205-317
@@ -889,6 +889,108 @@ __SIMT_DEVICE_FUNCTIONS_DECL__ inline float sinf(float x)
889 return s;889 return s;
890}890}
891 891 
892+__SIMT_DEVICE_FUNCTIONS_DECL__ inline float atan2f(float y, float x)
893+{
894+ // atan2(y, x) is the angle of the point (x, y) over the full circle. The polynomial below only covers
895+ // the first octant, so the magnitudes are reduced first and the octant is restored afterwards.
896+ float ay = __fabsf(y);
897+ float ax = __fabsf(x);
898+ 
899+ // Order the magnitudes so the ratio lo / hi never exceeds 1, which is the polynomial's valid range.
900+ bool y_gt_x = ay > ax;
901+ float hi = y_gt_x ? ay : ax;
902+ float lo = y_gt_x ? ax : ay;
903+ 
904+ float a = 0.0f;
905+ if (hi != 0.0f) {
906+ // The ratio lies in [0, 1]. atan is odd, so with z = r^2 the tail is even in r:
907+ // atan(r) = r + r^3 * P(z), P(z) = -0.33333197 + 0.19993925 z - 0.14207722 z^2 + 0.10640416 z^3
908+ // - 0.074792981 z^4 + 0.042200752 z^5 - 0.015681878 z^6 + 0.0027380611 z^7
909+ // P is minimax-fitted, not a Taylor truncation (leading term -0.33333197, not -1/3): the error is
910+ // flattened across all of [0, 1], so the coefficients cannot be extended by a series rule.
911+ float r = lo / hi;
912+ float z = r * r;
913+ float p = 0.0027380611281841993332f;
914+ p = __fma(z, p, -0.015681877732276916504f);
915+ p = __fma(z, p, 0.042200751602649688721f);
916+ p = __fma(z, p, -0.074792981147766113281f);
917+ p = __fma(z, p, 0.10640415549278259277f);
918+ p = __fma(z, p, -0.14207722246646881104f);
919+ p = __fma(z, p, 0.19993925094604492188f);
920+ p = __fma(z, p, -0.33333197236061096191f);
921+ // Assemble r + r^3 * P(z). r is the dominant term, so passing it as the fma addend keeps it exact
922+ // and confines rounding to the correction.
923+ float t = __fma(z * p, r, r);
924+ 
925+ // Rebuild the full-circle angle from the octant. |y| == |x| is special-cased so the diagonals come
926+ // out as the exactly rounded pi/4 and 3pi/4, and because inf/inf above makes r NaN.
927+ if (ay == ax) {
928+ a = signbit(x) ? 2.35619449615478515625f : 0.78539818525314331055f;
929+ } else if (y_gt_x) {
930+ // Steeper than the diagonal: the ratio r = ax/ay is the reciprocal of y/x, so
931+ // atan(y/x) = pi/2 - atan(x/y) = pi/2 - t. A negative x lies in the second quadrant, so pi/2 + t.
932+ float pio2 = 1.57079637050628662109f;
933+ a = signbit(x) ? (pio2 + t) : (pio2 - t);
934+ } else {
935+ // Shallow angles need no reflection; a negative x mirrors the first octant into the second.
936+ a = signbit(x) ? (3.14159274101257324219f - t) : t;
937+ }
938+ } else {
939+ // Both arguments are zero. Sign of x picks pi or 0, matching atan2(+-0, -0) == +-pi.
940+ a = signbit(x) ? 3.14159274101257324219f : 0.0f;
941+ }
942+ float result = signbit(y) ? -a : a;
943+ // Summing the magnitudes tests both arguments for NaN at once and propagates it as the result.
944+ float sum = ax + ay;
945+ if (__isnan(sum)) {
946+ result = sum;
947+ }
948+ // atan2 is odd in y, so the sign of y (including -0.0) is reapplied last.
949+ return result;
950+}
951+ 
952+/**
953+ * Computes atan(x) for float inputs.
954+ *
955+ * The implementation first handles special values with fixed IEEE-style semantics:
956+ * NaN propagates, and infinities map to signed pi/2.
957+ *
958+ * For finite inputs, it uses a reciprocal reduction for |x| > 1:
959+ * atan(x) = sign(x) * (pi/2 - atan(1/|x|))
960+ *
961+ * The reduced argument is then evaluated with an odd polynomial in x^2.
962+ *
963+ * @param x The input value.
964+ * @return The computed atanf(x) value.
965+ */
966+__SIMT_DEVICE_FUNCTIONS_DECL__ inline float atanf(float x)
967+{
968+ // Use reciprocal reduction for large magnitudes.
969+ const float abs_x = fabsf(x);
970+ const bool use_reciprocal = abs_x > 1.0f;
971+ 
972+ float reduced = use_reciprocal ? (1.0f / abs_x) : abs_x;
973+ const float reduced2 = reduced * reduced;
974+ 
975+ // Odd polynomial approximation in powers of x^2.
976+ float poly = fmaf(reduced2, 0.00245002890005707741f, -0.014396979473531246185f);
977+ poly = fmaf(reduced2, poly, 0.039849750697612762451f);
978+ poly = fmaf(reduced2, poly, -0.072529748082160949707f);
979+ poly = fmaf(reduced2, poly, 0.10518480092287063599f);
980+ poly = fmaf(reduced2, poly, -0.14171802997589111328f);
981+ poly = fmaf(reduced2, poly, 0.19988775253295898438f);
982+ poly = fmaf(reduced2, poly, -0.33332940936088562012f);
983+ poly *= reduced2;
984+ float result = fmaf(reduced, poly, reduced);
985+ 
986+ // Recover the pi/2 complement for the reciprocal branch.
987+ if (use_reciprocal) {
988+ result = fmaf(0.93318945169448852539f, 1.6832555532455444336f, -result);