Merged
float类型接口性能优化 #6308
xuyiyangAdd on Sep 21
float类型接口性能优化 #6308
Merged
Merged fromxuyiyang0324/asc-devkit_8577masterintocann/asc-devkitmaster
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); | ||