From 4c766f7e6ace6c1e4e5ae449e5b8768d13965117 Mon Sep 17 00:00:00 2001 From: Haoxiang Fei Date: Fri, 3 Jan 2025 12:47:07 +0800 Subject: [PATCH 1/3] add Double::to_uint() --- double/moon.pkg.json | 4 ++- double/to_uint.mbt | 54 +++++++++++++++++++++++++++++++++++++++++ double/to_uint_test.mbt | 35 ++++++++++++++++++++++++++ double/to_uint_wasm.mbt | 44 +++++++++++++++++++++++++++++++++ 4 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 double/to_uint.mbt create mode 100644 double/to_uint_test.mbt create mode 100644 double/to_uint_wasm.mbt diff --git a/double/moon.pkg.json b/double/moon.pkg.json index fef88f15e..eaeab5d0f 100644 --- a/double/moon.pkg.json +++ b/double/moon.pkg.json @@ -14,7 +14,9 @@ "pow_nonjs.mbt": ["not", "js"], "round_js.mbt": ["js"], "round_wasm.mbt": ["wasm", "wasm-gc"], - "round.mbt": ["not", "js", "wasm", "wasm-gc"] + "round.mbt": ["not", "js", "wasm", "wasm-gc"], + "to_uint_wasm.mbt": ["wasm", "wasm-gc"], + "to_uint.mbt": ["not", "wasm", "wasm-gc"] }, "test-import": [ "moonbitlang/core/test" diff --git a/double/to_uint.mbt b/double/to_uint.mbt new file mode 100644 index 000000000..b0d557b3a --- /dev/null +++ b/double/to_uint.mbt @@ -0,0 +1,54 @@ +// Copyright 2024 International Digital Economy Academy +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +///| +/// Converts a double-precision floating-point number to a 32-bit unsigned +/// integer. Handles special cases including NaN and numbers outside the valid +/// `UInt` range. +/// +/// Parameters: +/// +/// * `self` : The double-precision floating-point number to be converted. +/// +/// Returns an 32-bit unsigned integer value according to the following rules: +/// +/// * Returns 0 if the input is NaN +/// * Returns `@uint.max_value` (4294967295U) if the input is greater than or +/// equal to `@uint.max_value` +/// * Returns `@uint.min_value` (0U) if the input is less than or equal +/// to `@uint.min_value` +/// * Otherwise returns the integer part of the input by truncating towards zero +/// +/// Example: +/// +/// ```moonbit +/// test "Double::to_uint/normal" { +/// inspect!(42.0.to_uint(), content="42") +/// inspect!((-42.5).to_uint(), content="0") +/// inspect!((0.0 / 0.0).to_uint(), content="0") // NaN +/// inspect!((1.0 / 0.0).to_uint(), content="4294967295") // Infinity +/// inspect!((-1.0 / 0.0).to_uint(), content="0") // -Infinity +/// } +/// ``` +pub fn Double::to_uint(self : Double) -> UInt { + if self != self { + 0 + } else if self >= 4294967295.0 { + 4294967295U + } else if self <= 0 { + 0 + } else { + UInt::trunc_double(self) + } +} diff --git a/double/to_uint_test.mbt b/double/to_uint_test.mbt new file mode 100644 index 000000000..ed50493b6 --- /dev/null +++ b/double/to_uint_test.mbt @@ -0,0 +1,35 @@ +// Copyright 2024 International Digital Economy Academy +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +test "Double::to_uint" { + inspect!(0.0.to_uint(), content="0") + inspect!(1.0.to_uint(), content="1") + inspect!(1.5.to_uint(), content="1") + inspect!(1.9.to_uint(), content="1") + inspect!(2.0.to_uint(), content="2") + inspect!(2.5.to_uint(), content="2") + inspect!(2.9.to_uint(), content="2") + inspect!((-1.0).to_uint(), content="0") + inspect!((-1.5).to_uint(), content="0") + inspect!((-1.9).to_uint(), content="0") + inspect!((-2.0).to_uint(), content="0") + inspect!((-2.5).to_uint(), content="0") + inspect!((-2.9).to_uint(), content="0") + inspect!((0.0 / 0.0).to_uint(), content="0") + inspect!((1.0 / 0.0).to_uint(), content="4294967295") + inspect!((-1.0 / 0.0).to_uint(), content="0") + inspect!(4294967295.0.to_uint(), content="4294967295") + inspect!((-4294967296.0).to_uint(), content="0") + inspect!(4294967296.0.to_uint(), content="4294967295") +} diff --git a/double/to_uint_wasm.mbt b/double/to_uint_wasm.mbt new file mode 100644 index 000000000..e59d52fbe --- /dev/null +++ b/double/to_uint_wasm.mbt @@ -0,0 +1,44 @@ +// Copyright 2024 International Digital Economy Academy +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +///| +/// Converts a double-precision floating-point number to a 32-bit unsigned +/// integer. Handles special cases including NaN and numbers outside the valid +/// `UInt` range. +/// +/// Parameters: +/// +/// * `self` : The double-precision floating-point number to be converted. +/// +/// Returns an 32-bit unsigned integer value according to the following rules: +/// +/// * Returns 0 if the input is NaN +/// * Returns `@uint.max_value` (4294967295U) if the input is greater than or +/// equal to `@uint.max_value` +/// * Returns `@uint.min_value` (0U) if the input is less than or equal +/// to `@uint.min_value` +/// * Otherwise returns the integer part of the input by truncating towards zero +/// +/// Example: +/// +/// ```moonbit +/// test "Double::to_uint/normal" { +/// inspect!(42.0.to_uint(), content="42") +/// inspect!((-42.5).to_uint(), content="0") +/// inspect!((0.0 / 0.0).to_uint(), content="0") // NaN +/// inspect!((1.0 / 0.0).to_uint(), content="4294967295") // Infinity +/// inspect!((-1.0 / 0.0).to_uint(), content="0") // -Infinity +/// } +/// ``` +pub fn Double::to_uint(self : Double) -> UInt = "%f64.to_u32_saturate" From 3f012288d43ce06ea92f676da231c14f174604e6 Mon Sep 17 00:00:00 2001 From: Haoxiang Fei Date: Fri, 3 Jan 2025 13:00:27 +0800 Subject: [PATCH 2/3] add Double::to_uint64() --- builtin/double_to_int64_js.mbt | 77 ++++++++++++++++++++++++++++++ builtin/double_to_int64_native.mbt | 43 +++++++++++++++++ builtin/double_to_int64_test.mbt | 32 ++++++++++--- builtin/double_to_int64_wasm.mbt | 28 +++++++++++ builtin/int64_js.mbt | 30 ------------ 5 files changed, 174 insertions(+), 36 deletions(-) diff --git a/builtin/double_to_int64_js.mbt b/builtin/double_to_int64_js.mbt index 478b2464a..74c653ae1 100644 --- a/builtin/double_to_int64_js.mbt +++ b/builtin/double_to_int64_js.mbt @@ -12,6 +12,36 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| +extern "js" fn MyInt64::from_double(value : Double) -> MyInt64 = + #|(a) => { + #| if (isNaN(a)) { + #| return { hi: 0, lo: 0 }; + #| } + #| if (a >= 9223372036854775807) { + #| return { hi: 0x7fffffff, lo: 0xffffffff }; + #| } + #| if (a <= -9223372036854775808) { + #| return { hi: -2147483648, lo: 0 }; + #| } + #| let neg = false; + #| if (a < 0) { + #| neg = true; + #| a = -a; + #| } + #| let hi = (a * (1 / 0x100000000)) | 0; + #| let lo = a >>> 0; + #| if (neg) { + #| if (lo === 0) { + #| hi = ~hi + 1; + #| } else { + #| hi = ~hi; + #| lo = ~lo + 1; + #| } + #| } + #| return { hi, lo }; + #|} + ///| /// Converts a double-precision floating-point number to a 64-bit integer. /// Handles special cases including NaN and numbers outside the valid Int range. @@ -43,3 +73,50 @@ pub fn Double::to_int64(self : Double) -> Int64 { MyInt64::from_double(self).to_int64() } + +///| +extern "js" fn MyInt64::from_double_unsigned(value : Double) -> MyInt64 = + #|(a) => { + #| if (isNaN(a)) { + #| return { hi: 0, lo: 0 }; + #| } + #| if (a >= 18446744073709551615) { + #| return { hi: 0xffffffff, lo: 0xffffffff }; + #| } + #| if (a <= 0) { + #| return { hi: 0, lo: 0 }; + #| } + #| let hi = (a * (1 / 0x100000000)) | 0; + #| let lo = a >>> 0; + #| return { hi, lo }; + #|} + +///| +/// Converts a double-precision floating-point number to an unsigned 64-bit +/// integer, handling special cases and value ranges. +/// +/// Parameters: +/// +/// * `value` : The double-precision floating-point number to be converted. +/// +/// Returns an unsigned 64-bit integer value according to the following rules: +/// +/// * Returns 0 if the input is NaN +/// * Returns `UInt64::max_value` (18446744073709551615UL) if the input is +/// greater than or equal to `UInt64::max_value` +/// * Returns 0UL if the input is less than or equal to 0 +/// * Otherwise returns the integer part of the input by truncating towards zero +/// +/// Example: +/// +/// ```moonbit +/// test "Double::to_uint64" { +/// inspect!(42.0.to_uint64(), content="42") +/// inspect!((-42.5).to_uint64(), content="0") +/// inspect!((0.0 / 0.0).to_uint64(), content="0") // NaN +/// inspect!((1.0 / 0.0).to_uint64(), content="18446744073709551615") // Infinity +/// } +/// ``` +pub fn Double::to_uint64(self : Double) -> UInt64 { + MyInt64::from_double_unsigned(self).to_uint64() +} diff --git a/builtin/double_to_int64_native.mbt b/builtin/double_to_int64_native.mbt index 9a0548194..7a1281e32 100644 --- a/builtin/double_to_int64_native.mbt +++ b/builtin/double_to_int64_native.mbt @@ -54,3 +54,46 @@ pub fn Double::to_int64(self : Double) -> Int64 { self.to_unchecked_int64() } } + +///| +fn Double::to_unchecked_uint64(self : Double) -> UInt64 = "%f64_to_i64" + +///| +/// Converts a double-precision floating-point number to a 64-bit integer. +/// Handles special cases including NaN and numbers outside the valid Int range. +/// +/// Parameters: +/// +/// * `self` : The double-precision floating-point number to be converted. +/// +/// Returns an 64-bit integer value according to the following rules: +/// +/// * Returns 0 if the input is NaN +/// * Returns `@int64.max_value` (9223372036854775807L) if the input is greater than or +/// equal to `@int64.max_value` +/// * Returns `@int64.min_value` (-9223372036854775808L) if the input is less than or equal +/// to `@int64.min_value` +/// * Otherwise returns the integer part of the input by truncating towards zero +/// +/// Example: +/// +/// ```moonbit +/// test "Double::to_int64" { +/// inspect!(42.0.to_int64(), content="42") +/// inspect!((-42.5).to_int64(), content="-42") +/// inspect!((0.0 / 0.0).to_int64(), content="0") // NaN +/// inspect!((1.0 / 0.0).to_int64(), content="9223372036854775807") // Infinity +/// inspect!((-1.0 / 0.0).to_int64(), content="-9223372036854775808") // -Infinity +/// } +/// ``` +pub fn Double::to_uint64(self : Double) -> UInt64 { + if self != self { + 0 + } else if self >= 9223372036854775807 { + 18446744073709551615UL + } else if self <= 0 { + 0UL + } else { + self.to_unchecked_uint64() + } +} diff --git a/builtin/double_to_int64_test.mbt b/builtin/double_to_int64_test.mbt index 8c10dc953..62fdb6f09 100644 --- a/builtin/double_to_int64_test.mbt +++ b/builtin/double_to_int64_test.mbt @@ -20,12 +20,12 @@ test "Double::to_int64" { inspect!(2.0.to_int64(), content="2") inspect!(2.5.to_int64(), content="2") inspect!(2.9.to_int64(), content="2") - inspect!(-1.0.to_int64(), content="-1") - inspect!(-1.5.to_int64(), content="-1") - inspect!(-1.9.to_int64(), content="-1") - inspect!(-2.0.to_int64(), content="-2") - inspect!(-2.5.to_int64(), content="-2") - inspect!(-2.9.to_int64(), content="-2") + inspect!((-1.0).to_int64(), content="-1") + inspect!((-1.5).to_int64(), content="-1") + inspect!((-1.9).to_int64(), content="-1") + inspect!((-2.0).to_int64(), content="-2") + inspect!((-2.5).to_int64(), content="-2") + inspect!((-2.9).to_int64(), content="-2") inspect!((0.0 / 0.0).to_int64(), content="0") inspect!((1.0 / 0.0).to_int64(), content="9223372036854775807") inspect!((-1.0 / 0.0).to_int64(), content="-9223372036854775808") @@ -34,3 +34,23 @@ test "Double::to_int64" { inspect!(9223372036854775808.0.to_int64(), content="9223372036854775807") inspect!((-9223372036854775809.0).to_int64(), content="-9223372036854775808") } + +test "Double::to_uint64" { + inspect!(0.0.to_uint64(), content="0") + inspect!(1.0.to_uint64(), content="1") + inspect!(1.5.to_uint64(), content="1") + inspect!(1.9.to_uint64(), content="1") + inspect!(2.0.to_uint64(), content="2") + inspect!(2.5.to_uint64(), content="2") + inspect!(2.9.to_uint64(), content="2") + inspect!((-1.0).to_uint64(), content="0") + inspect!((-1.5).to_uint64(), content="0") + inspect!((-1.9).to_uint64(), content="0") + inspect!((-2.0).to_uint64(), content="0") + inspect!((-2.5).to_uint64(), content="0") + inspect!((-2.9).to_uint64(), content="0") + inspect!((0.0 / 0.0).to_uint64(), content="0") + inspect!((1.0 / 0.0).to_uint64(), content="18446744073709551615") + inspect!((-1.0 / 0.0).to_uint64(), content="0") + inspect!(18446744073709551615.0.to_uint64(), content="18446744073709551615") +} diff --git a/builtin/double_to_int64_wasm.mbt b/builtin/double_to_int64_wasm.mbt index 74741a374..68c3d4553 100644 --- a/builtin/double_to_int64_wasm.mbt +++ b/builtin/double_to_int64_wasm.mbt @@ -41,3 +41,31 @@ /// } /// ``` pub fn Double::to_int64(self : Double) -> Int64 = "%f64_to_i64_saturate" + +///| +/// Converts a double-precision floating-point number to an unsigned 64-bit +/// integer, handling special cases and value ranges. +/// +/// Parameters: +/// +/// * `value` : The double-precision floating-point number to be converted. +/// +/// Returns an unsigned 64-bit integer value according to the following rules: +/// +/// * Returns 0 if the input is NaN +/// * Returns `UInt64::max_value` (18446744073709551615UL) if the input is +/// greater than or equal to `UInt64::max_value` +/// * Returns 0UL if the input is less than or equal to 0 +/// * Otherwise returns the integer part of the input by truncating towards zero +/// +/// Example: +/// +/// ```moonbit +/// test "Double::to_uint64" { +/// inspect!(42.0.to_uint64(), content="42") +/// inspect!((-42.5).to_uint64(), content="0") +/// inspect!((0.0 / 0.0).to_uint64(), content="0") // NaN +/// inspect!((1.0 / 0.0).to_uint64(), content="18446744073709551615") // Infinity +/// } +/// ``` +pub fn Double::to_uint64(self : Double) -> UInt64 = "%f64.to_u64_saturate" diff --git a/builtin/int64_js.mbt b/builtin/int64_js.mbt index 1060c3d34..c879de007 100644 --- a/builtin/int64_js.mbt +++ b/builtin/int64_js.mbt @@ -320,36 +320,6 @@ fn MyInt64::to_uint(self : MyInt64) -> UInt { self.lo.reinterpret_as_uint() } -///| -extern "js" fn MyInt64::from_double(value : Double) -> MyInt64 = - #|(a) => { - #| if (isNaN(a)) { - #| return { hi: 0, lo: 0 }; - #| } - #| if (a >= 9223372036854775807) { - #| return { hi: 0x7fffffff, lo: 0xffffffff }; - #| } - #| if (a <= -9223372036854775808) { - #| return { hi: -2147483648, lo: 0 }; - #| } - #| let neg = false; - #| if (a < 0) { - #| neg = true; - #| a = -a; - #| } - #| let hi = (a * (1 / 0x100000000)) | 0; - #| let lo = a >>> 0; - #| if (neg) { - #| if (lo === 0) { - #| hi = ~hi + 1; - #| } else { - #| hi = ~hi; - #| lo = ~lo + 1; - #| } - #| } - #| return { hi, lo }; - #|} - ///| extern "js" fn MyInt64::to_double(self : MyInt64) -> Double = #|(a) => a.hi * 4294967296.0 + (a.lo >>> 0) From 16456338d826ae6cadd73d8637c220df99c5c14f Mon Sep 17 00:00:00 2001 From: Haoxiang Fei Date: Fri, 3 Jan 2025 15:46:31 +0800 Subject: [PATCH 3/3] update moon info --- builtin/builtin.mbti | 1 + double/double.mbti | 1 + 2 files changed, 2 insertions(+) diff --git a/builtin/builtin.mbti b/builtin/builtin.mbti index e45ec029e..65dd2aabd 100644 --- a/builtin/builtin.mbti +++ b/builtin/builtin.mbti @@ -634,6 +634,7 @@ impl Double { to_int(Double) -> Int to_int64(Double) -> Int64 to_json(Double) -> Json + to_uint64(Double) -> UInt64 until(Double, Double, step~ : Double = .., inclusive~ : Bool = ..) -> Iter[Double] upto(Double, Double, inclusive~ : Bool = ..) -> Iter[Double] //deprecated } diff --git a/double/double.mbti b/double/double.mbti index 45a80e529..0a383e0b8 100644 --- a/double/double.mbti +++ b/double/double.mbti @@ -38,6 +38,7 @@ impl Double { to_be_bytes(Double) -> Bytes to_le_bytes(Double) -> Bytes to_string(Double) -> String + to_uint(Double) -> UInt trunc(Double) -> Double } impl Hash for Double