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