2021-01-18 15:20:06 +03:00
|
|
|
// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved.
|
2020-07-11 20:03:59 +03:00
|
|
|
// Use of this source code is governed by an MIT license that can be found in the LICENSE file.
|
2019-10-15 04:46:40 +03:00
|
|
|
module builtin
|
|
|
|
|
2020-07-16 20:01:22 +03:00
|
|
|
import strconv
|
2020-02-26 14:14:06 +03:00
|
|
|
|
2020-04-14 19:27:30 +03:00
|
|
|
#include <float.h>
|
2021-01-06 01:01:10 +03:00
|
|
|
/*
|
|
|
|
-----------------------------------
|
|
|
|
----- f64 to string functions -----
|
|
|
|
*/
|
|
|
|
// str return a `f64` as `string` in suitable notation.
|
2020-02-26 14:14:06 +03:00
|
|
|
[inline]
|
2020-06-18 23:33:41 +03:00
|
|
|
pub fn (x f64) str() string {
|
2021-05-24 05:20:45 +03:00
|
|
|
unsafe {
|
|
|
|
f := strconv.Float64u{
|
|
|
|
f: x
|
|
|
|
}
|
|
|
|
if f.u == strconv.double_minus_zero {
|
|
|
|
return '-0'
|
|
|
|
}
|
|
|
|
if f.u == strconv.double_plus_zero {
|
|
|
|
return '0'
|
|
|
|
}
|
|
|
|
}
|
2020-05-27 06:42:48 +03:00
|
|
|
abs_x := f64_abs(x)
|
2020-06-18 23:33:41 +03:00
|
|
|
if abs_x >= 0.0001 && abs_x < 1.0e6 {
|
2020-07-16 20:01:22 +03:00
|
|
|
return strconv.f64_to_str_l(x)
|
2020-05-27 06:42:48 +03:00
|
|
|
} else {
|
2020-07-16 20:01:22 +03:00
|
|
|
return strconv.ftoa_64(x)
|
2020-05-27 06:42:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-24 05:20:45 +03:00
|
|
|
// strg return a `f64` as `string` in "g" printf format
|
|
|
|
[inline]
|
|
|
|
pub fn (x f64) strg() string {
|
|
|
|
if x == 0 {
|
|
|
|
return '0'
|
|
|
|
}
|
|
|
|
abs_x := f64_abs(x)
|
|
|
|
if abs_x >= 0.0001 && abs_x < 1.0e6 {
|
|
|
|
return strconv.f64_to_str_l_no_dot(x)
|
|
|
|
} else {
|
|
|
|
return strconv.ftoa_64(x)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-12 00:58:15 +03:00
|
|
|
// str returns the value of the `float_literal` as a `string`.
|
2020-06-18 23:33:41 +03:00
|
|
|
[inline]
|
2021-01-12 00:58:15 +03:00
|
|
|
pub fn (d float_literal) str() string {
|
2020-06-18 23:33:41 +03:00
|
|
|
return f64(d).str()
|
|
|
|
}
|
|
|
|
|
2021-02-07 02:01:37 +03:00
|
|
|
// strsci returns the `f64` as a `string` in scientific notation with `digit_num` decimals displayed, max 17 digits.
|
2021-01-06 01:01:10 +03:00
|
|
|
// Example: assert f64(1.234).strsci(3) == '1.234e+00'
|
2020-02-26 14:14:06 +03:00
|
|
|
[inline]
|
|
|
|
pub fn (x f64) strsci(digit_num int) string {
|
|
|
|
mut n_digit := digit_num
|
|
|
|
if n_digit < 1 {
|
|
|
|
n_digit = 1
|
|
|
|
} else if n_digit > 17 {
|
|
|
|
n_digit = 17
|
|
|
|
}
|
2020-07-16 20:01:22 +03:00
|
|
|
return strconv.f64_to_str(x, n_digit)
|
2020-02-26 14:14:06 +03:00
|
|
|
}
|
|
|
|
|
2021-01-06 01:01:10 +03:00
|
|
|
// strlong returns a decimal notation of the `f64` as a `string`.
|
|
|
|
// Example: assert f64(1.23456).strlong() == '1.23456'
|
2020-02-26 14:14:06 +03:00
|
|
|
[inline]
|
|
|
|
pub fn (x f64) strlong() string {
|
2020-07-16 20:01:22 +03:00
|
|
|
return strconv.f64_to_str_l(x)
|
2019-10-15 04:46:40 +03:00
|
|
|
}
|
|
|
|
|
2021-01-06 01:01:10 +03:00
|
|
|
/*
|
|
|
|
-----------------------------------
|
|
|
|
----- f32 to string functions -----
|
|
|
|
*/
|
|
|
|
// str returns a `f32` as `string` in suitable notation.
|
2020-02-26 14:14:06 +03:00
|
|
|
[inline]
|
2020-06-18 23:33:41 +03:00
|
|
|
pub fn (x f32) str() string {
|
2021-05-24 05:20:45 +03:00
|
|
|
unsafe {
|
|
|
|
f := strconv.Float32u{
|
|
|
|
f: x
|
|
|
|
}
|
|
|
|
if f.u == strconv.single_minus_zero {
|
|
|
|
return '-0'
|
|
|
|
}
|
|
|
|
if f.u == strconv.single_plus_zero {
|
|
|
|
return '0'
|
|
|
|
}
|
|
|
|
}
|
2020-06-18 23:33:41 +03:00
|
|
|
abs_x := f32_abs(x)
|
|
|
|
if abs_x >= 0.0001 && abs_x < 1.0e6 {
|
2020-07-16 20:01:22 +03:00
|
|
|
return strconv.f32_to_str_l(x)
|
2020-06-18 23:33:41 +03:00
|
|
|
} else {
|
2020-07-16 20:01:22 +03:00
|
|
|
return strconv.ftoa_32(x)
|
2020-06-18 23:33:41 +03:00
|
|
|
}
|
2019-10-15 04:46:40 +03:00
|
|
|
}
|
|
|
|
|
2021-05-24 05:20:45 +03:00
|
|
|
// strg return a `f32` as `string` in "g" printf format
|
|
|
|
[inline]
|
|
|
|
pub fn (x f32) strg() string {
|
|
|
|
if x == 0 {
|
|
|
|
return '0'
|
|
|
|
}
|
|
|
|
abs_x := f32_abs(x)
|
|
|
|
if abs_x >= 0.0001 && abs_x < 1.0e6 {
|
|
|
|
return strconv.f32_to_str_l_no_dot(x)
|
|
|
|
} else {
|
|
|
|
return strconv.ftoa_32(x)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-06 01:01:10 +03:00
|
|
|
// strsci returns the `f32` as a `string` in scientific notation with `digit_num` deciamals displayed, max 8 digits.
|
|
|
|
// Example: assert f32(1.234).strsci(3) == '1.234e+00'
|
2020-02-26 14:14:06 +03:00
|
|
|
[inline]
|
|
|
|
pub fn (x f32) strsci(digit_num int) string {
|
|
|
|
mut n_digit := digit_num
|
|
|
|
if n_digit < 1 {
|
|
|
|
n_digit = 1
|
|
|
|
} else if n_digit > 8 {
|
|
|
|
n_digit = 8
|
|
|
|
}
|
2020-07-16 20:01:22 +03:00
|
|
|
return strconv.f32_to_str(x, n_digit)
|
2019-12-17 01:07:13 +03:00
|
|
|
}
|
|
|
|
|
2021-01-06 01:01:10 +03:00
|
|
|
// strlong returns a decimal notation of the `f32` as a `string`.
|
2020-02-26 14:14:06 +03:00
|
|
|
[inline]
|
|
|
|
pub fn (x f32) strlong() string {
|
2020-07-16 20:01:22 +03:00
|
|
|
return strconv.f32_to_str_l(x)
|
2019-12-17 01:07:13 +03:00
|
|
|
}
|
|
|
|
|
2021-01-06 01:01:10 +03:00
|
|
|
/*
|
|
|
|
-----------------------
|
|
|
|
----- C functions -----
|
|
|
|
*/
|
|
|
|
// f32_abs returns the absolute value of `a` as a `f32` value.
|
|
|
|
// Example: assert f32_abs(-2.0) == 2.0
|
2020-02-16 18:13:45 +03:00
|
|
|
[inline]
|
2020-06-18 23:33:41 +03:00
|
|
|
pub fn f32_abs(a f32) f32 {
|
2021-03-24 21:39:59 +03:00
|
|
|
return if a < 0 { -a } else { a }
|
2019-12-18 21:56:30 +03:00
|
|
|
}
|
|
|
|
|
2021-01-06 01:01:10 +03:00
|
|
|
// f64_abs returns the absolute value of `a` as a `f64` value.
|
|
|
|
// Example: assert f64_abs(-2.0) == f64(2.0)
|
2020-02-16 18:13:45 +03:00
|
|
|
[inline]
|
2019-12-18 21:56:30 +03:00
|
|
|
fn f64_abs(a f64) f64 {
|
2021-03-24 21:39:59 +03:00
|
|
|
return if a < 0 { -a } else { a }
|
2019-12-18 21:56:30 +03:00
|
|
|
}
|
2019-10-15 04:46:40 +03:00
|
|
|
|
2021-01-06 01:01:10 +03:00
|
|
|
// f32_max returns the largest `f32` of input `a` and `b`.
|
|
|
|
// Example: assert f32_max(2.0,3.0) == 3.0
|
2020-02-16 18:13:45 +03:00
|
|
|
[inline]
|
2020-10-15 13:32:28 +03:00
|
|
|
pub fn f32_max(a f32, b f32) f32 {
|
2021-03-24 21:39:59 +03:00
|
|
|
return if a > b { a } else { b }
|
2019-10-15 04:46:40 +03:00
|
|
|
}
|
2019-12-18 21:56:30 +03:00
|
|
|
|
2021-01-06 01:01:10 +03:00
|
|
|
// f32_min returns the smallest `f32` of input `a` and `b`.
|
|
|
|
// Example: assert f32_min(2.0,3.0) == 2.0
|
2020-06-04 20:47:41 +03:00
|
|
|
[inline]
|
2020-10-15 13:32:28 +03:00
|
|
|
pub fn f32_min(a f32, b f32) f32 {
|
2021-03-24 21:39:59 +03:00
|
|
|
return if a < b { a } else { b }
|
2019-10-15 04:46:40 +03:00
|
|
|
}
|
|
|
|
|
2021-01-06 01:01:10 +03:00
|
|
|
// f64_max returns the largest `f64` of input `a` and `b`.
|
|
|
|
// Example: assert f64_max(2.0,3.0) == 3.0
|
2020-06-04 20:47:41 +03:00
|
|
|
[inline]
|
2020-10-15 13:32:28 +03:00
|
|
|
pub fn f64_max(a f64, b f64) f64 {
|
2021-03-24 21:39:59 +03:00
|
|
|
return if a > b { a } else { b }
|
2019-10-15 04:46:40 +03:00
|
|
|
}
|
2019-12-18 21:56:30 +03:00
|
|
|
|
2021-01-06 01:01:10 +03:00
|
|
|
// f64_min returns the smallest `f64` of input `a` and `b`.
|
|
|
|
// Example: assert f64_min(2.0,3.0) == 2.0
|
2020-06-04 20:47:41 +03:00
|
|
|
[inline]
|
2020-10-15 13:32:28 +03:00
|
|
|
fn f64_min(a f64, b f64) f64 {
|
2021-03-24 21:39:59 +03:00
|
|
|
return if a < b { a } else { b }
|
2019-10-15 04:46:40 +03:00
|
|
|
}
|
2019-12-18 21:56:30 +03:00
|
|
|
|
2021-01-06 01:01:10 +03:00
|
|
|
// eq_epsilon returns true if the `f32` is equal to input `b`.
|
|
|
|
// using an epsilon of typically 1E-5 or higher (backend/compiler dependent).
|
|
|
|
// Example: assert f32(2.0).eq_epsilon(2.0)
|
2020-06-04 20:47:41 +03:00
|
|
|
[inline]
|
2020-06-04 21:26:18 +03:00
|
|
|
pub fn (a f32) eq_epsilon(b f32) bool {
|
2020-06-04 20:47:41 +03:00
|
|
|
hi := f32_max(f32_abs(a), f32_abs(b))
|
|
|
|
delta := f32_abs(a - b)
|
|
|
|
if hi > f32(1.0) {
|
|
|
|
return delta <= hi * (4 * f32(C.FLT_EPSILON))
|
|
|
|
} else {
|
|
|
|
return (1 / (4 * f32(C.FLT_EPSILON))) * delta <= hi
|
|
|
|
}
|
2019-10-15 04:46:40 +03:00
|
|
|
}
|
2019-12-18 21:56:30 +03:00
|
|
|
|
2021-01-06 01:01:10 +03:00
|
|
|
// eq_epsilon returns true if the `f64` is equal to input `b`.
|
|
|
|
// using an epsilon of typically 1E-9 or higher (backend/compiler dependent).
|
|
|
|
// Example: assert f64(2.0).eq_epsilon(2.0)
|
2020-06-04 20:47:41 +03:00
|
|
|
[inline]
|
2020-06-04 21:26:18 +03:00
|
|
|
pub fn (a f64) eq_epsilon(b f64) bool {
|
2020-06-04 20:47:41 +03:00
|
|
|
hi := f64_max(f64_abs(a), f64_abs(b))
|
|
|
|
delta := f64_abs(a - b)
|
|
|
|
if hi > 1.0 {
|
|
|
|
return delta <= hi * (4 * f64(C.DBL_EPSILON))
|
|
|
|
} else {
|
|
|
|
return (1 / (4 * f64(C.DBL_EPSILON))) * delta <= hi
|
|
|
|
}
|
2019-10-15 04:46:40 +03:00
|
|
|
}
|