1 | // Copyright (c) 2019-2023 Alexander Medvednikov. All rights reserved. |
2 | // Use of this source code is governed by an MIT license that can be found in the LICENSE file. |
3 | module builtin |
4 | |
5 | // TODO implement compile time conditional include |
6 | // [if !nofloat] |
7 | import strconv |
8 | |
9 | #include <float.h> |
10 | /* |
11 | ----------------------------------- |
12 | ----- f64 to string functions ----- |
13 | */ |
14 | // str return a `f64` as `string` in suitable notation. |
15 | [inline] |
16 | pub fn (x f64) str() string { |
17 | unsafe { |
18 | f := strconv.Float64u{ |
19 | f: x |
20 | } |
21 | if f.u == strconv.double_minus_zero { |
22 | return '-0.0' |
23 | } |
24 | if f.u == strconv.double_plus_zero { |
25 | return '0.0' |
26 | } |
27 | } |
28 | abs_x := f64_abs(x) |
29 | if abs_x >= 0.0001 && abs_x < 1.0e6 { |
30 | return strconv.f64_to_str_l(x) |
31 | } else { |
32 | return strconv.ftoa_64(x) |
33 | } |
34 | } |
35 | |
36 | // strg return a `f64` as `string` in "g" printf format |
37 | [inline] |
38 | pub fn (x f64) strg() string { |
39 | if x == 0 { |
40 | return '0.0' |
41 | } |
42 | abs_x := f64_abs(x) |
43 | if abs_x >= 0.0001 && abs_x < 1.0e6 { |
44 | return strconv.f64_to_str_l_with_dot(x) |
45 | } else { |
46 | return strconv.ftoa_64(x) |
47 | } |
48 | } |
49 | |
50 | // str returns the value of the `float_literal` as a `string`. |
51 | [inline] |
52 | pub fn (d float_literal) str() string { |
53 | return f64(d).str() |
54 | } |
55 | |
56 | // strsci returns the `f64` as a `string` in scientific notation with `digit_num` decimals displayed, max 17 digits. |
57 | // Example: assert f64(1.234).strsci(3) == '1.234e+00' |
58 | [inline] |
59 | pub fn (x f64) strsci(digit_num int) string { |
60 | mut n_digit := digit_num |
61 | if n_digit < 1 { |
62 | n_digit = 1 |
63 | } else if n_digit > 17 { |
64 | n_digit = 17 |
65 | } |
66 | return strconv.f64_to_str(x, n_digit) |
67 | } |
68 | |
69 | // strlong returns a decimal notation of the `f64` as a `string`. |
70 | // Example: assert f64(1.23456).strlong() == '1.23456' |
71 | [inline] |
72 | pub fn (x f64) strlong() string { |
73 | return strconv.f64_to_str_l(x) |
74 | } |
75 | |
76 | /* |
77 | ----------------------------------- |
78 | ----- f32 to string functions ----- |
79 | */ |
80 | // str returns a `f32` as `string` in suitable notation. |
81 | [inline] |
82 | pub fn (x f32) str() string { |
83 | unsafe { |
84 | f := strconv.Float32u{ |
85 | f: x |
86 | } |
87 | if f.u == strconv.single_minus_zero { |
88 | return '-0.0' |
89 | } |
90 | if f.u == strconv.single_plus_zero { |
91 | return '0.0' |
92 | } |
93 | } |
94 | abs_x := f32_abs(x) |
95 | if abs_x >= 0.0001 && abs_x < 1.0e6 { |
96 | return strconv.f32_to_str_l(x) |
97 | } else { |
98 | return strconv.ftoa_32(x) |
99 | } |
100 | } |
101 | |
102 | // strg return a `f32` as `string` in "g" printf format |
103 | [inline] |
104 | pub fn (x f32) strg() string { |
105 | if x == 0 { |
106 | return '0.0' |
107 | } |
108 | abs_x := f32_abs(x) |
109 | if abs_x >= 0.0001 && abs_x < 1.0e6 { |
110 | return strconv.f32_to_str_l_with_dot(x) |
111 | } else { |
112 | return strconv.ftoa_32(x) |
113 | } |
114 | } |
115 | |
116 | // strsci returns the `f32` as a `string` in scientific notation with `digit_num` decimals displayed, max 8 digits. |
117 | // Example: assert f32(1.234).strsci(3) == '1.234e+00' |
118 | [inline] |
119 | pub fn (x f32) strsci(digit_num int) string { |
120 | mut n_digit := digit_num |
121 | if n_digit < 1 { |
122 | n_digit = 1 |
123 | } else if n_digit > 8 { |
124 | n_digit = 8 |
125 | } |
126 | return strconv.f32_to_str(x, n_digit) |
127 | } |
128 | |
129 | // strlong returns a decimal notation of the `f32` as a `string`. |
130 | [inline] |
131 | pub fn (x f32) strlong() string { |
132 | return strconv.f32_to_str_l(x) |
133 | } |
134 | |
135 | /* |
136 | ----------------------- |
137 | ----- C functions ----- |
138 | */ |
139 | // f32_abs returns the absolute value of `a` as a `f32` value. |
140 | // Example: assert f32_abs(-2.0) == 2.0 |
141 | [inline] |
142 | pub fn f32_abs(a f32) f32 { |
143 | return if a < 0 { -a } else { a } |
144 | } |
145 | |
146 | // f64_abs returns the absolute value of `a` as a `f64` value. |
147 | // Example: assert f64_abs(-2.0) == f64(2.0) |
148 | [inline] |
149 | fn f64_abs(a f64) f64 { |
150 | return if a < 0 { -a } else { a } |
151 | } |
152 | |
153 | // f32_max returns the largest `f32` of input `a` and `b`. |
154 | // Example: assert f32_max(2.0,3.0) == 3.0 |
155 | [inline] |
156 | pub fn f32_max(a f32, b f32) f32 { |
157 | return if a > b { a } else { b } |
158 | } |
159 | |
160 | // f32_min returns the smallest `f32` of input `a` and `b`. |
161 | // Example: assert f32_min(2.0,3.0) == 2.0 |
162 | [inline] |
163 | pub fn f32_min(a f32, b f32) f32 { |
164 | return if a < b { a } else { b } |
165 | } |
166 | |
167 | // f64_max returns the largest `f64` of input `a` and `b`. |
168 | // Example: assert f64_max(2.0,3.0) == 3.0 |
169 | [inline] |
170 | pub fn f64_max(a f64, b f64) f64 { |
171 | return if a > b { a } else { b } |
172 | } |
173 | |
174 | // f64_min returns the smallest `f64` of input `a` and `b`. |
175 | // Example: assert f64_min(2.0,3.0) == 2.0 |
176 | [inline] |
177 | fn f64_min(a f64, b f64) f64 { |
178 | return if a < b { a } else { b } |
179 | } |
180 | |
181 | // eq_epsilon returns true if the `f32` is equal to input `b`. |
182 | // using an epsilon of typically 1E-5 or higher (backend/compiler dependent). |
183 | // Example: assert f32(2.0).eq_epsilon(2.0) |
184 | [inline] |
185 | pub fn (a f32) eq_epsilon(b f32) bool { |
186 | hi := f32_max(f32_abs(a), f32_abs(b)) |
187 | delta := f32_abs(a - b) |
188 | if hi > f32(1.0) { |
189 | return delta <= hi * (4 * f32(C.FLT_EPSILON)) |
190 | } else { |
191 | return (1 / (4 * f32(C.FLT_EPSILON))) * delta <= hi |
192 | } |
193 | } |
194 | |
195 | // eq_epsilon returns true if the `f64` is equal to input `b`. |
196 | // using an epsilon of typically 1E-9 or higher (backend/compiler dependent). |
197 | // Example: assert f64(2.0).eq_epsilon(2.0) |
198 | [inline] |
199 | pub fn (a f64) eq_epsilon(b f64) bool { |
200 | hi := f64_max(f64_abs(a), f64_abs(b)) |
201 | delta := f64_abs(a - b) |
202 | if hi > 1.0 { |
203 | return delta <= hi * (4 * f64(C.DBL_EPSILON)) |
204 | } else { |
205 | return (1 / (4 * f64(C.DBL_EPSILON))) * delta <= hi |
206 | } |
207 | } |