ftz 0.0.1
Fast, reproducible floating-point arithmetic
Loading...
Searching...
No Matches
log.h
Go to the documentation of this file.
1#pragma once
2#include "ftz/config.h"
3#include "native/attributes.h"
4#include "ftz/math/float.h"
5namespace ftz { namespace detail { namespace math {
6 struct log_result { unsigned int bits, valid; };
7 // Precondition: finite x in [-.5,1], zero or canonical normal. Tiny input
8 // returns its original bits before squaring. Fixed x+x*x*P(x) graph; no divide.
9 template <bool Hardware = FTZ_FP32_HARDWARE_FTZ != 0>
10 [[nodiscard]] native_constexpr native_inline native_const float log1p_kernel(float x) {
11 unsigned int word = fp32_encode(x);
12 if ((word & 0x7fffffffu) <= 0x33000000u) return x;
13 float z = fp32_mul<true,Hardware>(x,x);
14 float t,h;
15 if ((word & 0x80000000u) != 0u) {
16 t = fp32_fma<true,Hardware>(x,fp32_decode(0x40800000u),fp32_decode(0x3f800000u));
17 h = fp32_decode(0xb44f5480u);
18 h = fp32_fma<true,Hardware>(h,t,fp32_decode(0x352754efu));
19 h = fp32_fma<true,Hardware>(h,t,fp32_decode(0xb5bb75dbu));
20 h = fp32_fma<true,Hardware>(h,t,fp32_decode(0x369a1c19u));
21 h = fp32_fma<true,Hardware>(h,t,fp32_decode(0xb7866f43u));
22 h = fp32_fma<true,Hardware>(h,t,fp32_decode(0x3861235au));
23 h = fp32_fma<true,Hardware>(h,t,fp32_decode(0xb93e98dfu));
24 h = fp32_fma<true,Hardware>(h,t,fp32_decode(0x3a24a041u));
25 h = fp32_fma<true,Hardware>(h,t,fp32_decode(0xbb117f6au));
26 h = fp32_fma<true,Hardware>(h,t,fp32_decode(0x3c04b7c5u));
27 h = fp32_fma<true,Hardware>(h,t,fp32_decode(0xbcfda364u));
28 h = fp32_fma<true,Hardware>(h,t,fp32_decode(0x3e029133u));
29 h = fp32_fma<true,Hardware>(h,t,fp32_decode(0xbf1a5884u));
30 }
31 else {
32 t = fp32_fma<true,Hardware>(x,fp32_decode(0x40000000u),fp32_decode(0xbf800000u));
33 h = fp32_decode(0xb29c7ee2u);
34 h = fp32_fma<true,Hardware>(h,t,fp32_decode(0x3378ea39u));
35 h = fp32_fma<true,Hardware>(h,t,fp32_decode(0xb3faaccbu));
36 h = fp32_fma<true,Hardware>(h,t,fp32_decode(0x34c9e1cdu));
37 h = fp32_fma<true,Hardware>(h,t,fp32_decode(0xb5b13b5eu));
38 h = fp32_fma<true,Hardware>(h,t,fp32_decode(0x36902a0au));
39 h = fp32_fma<true,Hardware>(h,t,fp32_decode(0xb76af011u));
40 h = fp32_fma<true,Hardware>(h,t,fp32_decode(0x38423d8au));
41 h = fp32_fma<true,Hardware>(h,t,fp32_decode(0xb9225d51u));
42 h = fp32_fma<true,Hardware>(h,t,fp32_decode(0x3a0988b0u));
43 h = fp32_fma<true,Hardware>(h,t,fp32_decode(0xbaed1a41u));
44 h = fp32_fma<true,Hardware>(h,t,fp32_decode(0x3bd13ce0u));
45 h = fp32_fma<true,Hardware>(h,t,fp32_decode(0xbcbeef90u));
46 h = fp32_fma<true,Hardware>(h,t,fp32_decode(0x3db786beu));
47 h = fp32_fma<true,Hardware>(h,t,fp32_decode(0xbec19b82u));
48 }
49 return fp32_fma<true,Hardware>(z,h,x);
50 }
51 template <bool Hardware = FTZ_FP32_HARDWARE_FTZ != 0>
52 [[nodiscard]] native_constexpr native_inline native_const log_result log_words(unsigned int word) {
53 unsigned int magnitude = word & 0x7fffffffu;
54 log_result result;result.bits=0x7fc00000u;result.valid=0u;
55 if (magnitude > 0x7f800000u) return result;
56 if (magnitude < 0x00800000u) {
57 result.bits=0xff800000u;result.valid=1u;return result;
58 }
59 if ((word & 0x80000000u) != 0u) return result;
60 result.valid=1u;
61 if (magnitude == 0x7f800000u) {result.bits=word;return result;}
62 int exponent=(int)(word >> 23)-127;
63 unsigned int mantissa=(word & 0x007fffffu) | 0x3f800000u;
64 if (mantissa >= 0x3fc00000u) {mantissa-=0x00800000u;exponent+=1;}
65 // m in [.75,1.5): m-1 is exact by Sterbenz, including the neighborhood of1.
66 float r=fp32_add<true,Hardware>(fp32_decode(mantissa),-1.0f);
67 float p=log1p_kernel<Hardware>(r);
68 float e=(float)exponent;
69 // ln2_hi clears the low8 significand bits; ln2_low is the rounded residue.
70 float low=fp32_fma<true,Hardware>(e,fp32_decode(0x35bfbe8eu),p);
71 result.bits=fp32_encode(fp32_fma<true,Hardware>(e,fp32_decode(0x3f317200u),low));
72 return result;
73 }
74 template <bool Hardware = FTZ_FP32_HARDWARE_FTZ != 0>
75 [[nodiscard]] native_constexpr native_inline native_const log_result log1p_words(unsigned int word) {
76 unsigned int magnitude=word & 0x7fffffffu;
77 bool negative=(word & 0x80000000u) != 0u;
78 log_result result;result.bits=0x7fc00000u;result.valid=0u;
79 if (magnitude > 0x7f800000u || (negative && magnitude > 0x3f800000u)) return result;
80 result.valid=1u;
81 if (magnitude < 0x00800000u) {result.bits=word & 0x80000000u;return result;}
82 if (negative && magnitude == 0x3f800000u) {result.bits=0xff800000u;return result;}
83 if (magnitude == 0x7f800000u) {result.bits=word;return result;}
84 if (magnitude <= 0x33000000u) {result.bits=word;return result;}
85 float x=fp32_decode(word);
86 if ((!negative && magnitude <= 0x3f800000u) || (negative && magnitude <= 0x3f000000u)) {
87 result.bits=fp32_encode(log1p_kernel<Hardware>(x));return result;
88 }
89 // Negative outer inputs use an exact Sterbenz sum. For x>1 this rounded
90 // sum is part of the declared approximation, not a correctly-rounded log1p.
91 return log_words<Hardware>(fp32_encode(fp32_add<true,Hardware>(1.0f,x)));
92 }
93 template <bool Hardware = FTZ_FP32_HARDWARE_FTZ != 0>
94 [[nodiscard]] native_constexpr native_inline native_const float log(float value) {
95 return fp32_decode(log_words<Hardware>(fp32_encode(value)).bits);
96 }
97 template <bool Hardware = FTZ_FP32_HARDWARE_FTZ != 0>
98 [[nodiscard]] native_constexpr native_inline native_const float log1p(float value) {
99 return fp32_decode(log1p_words<Hardware>(fp32_encode(value)).bits);
100 }
101}}}
102
FP32 bit casts, precise arithmetic and signed flush-to-zero normalization.