diff --git a/stdlib/src/builtin/bin.mojo b/stdlib/src/builtin/bin.mojo new file mode 100644 index 000000000..94adfdde3 --- /dev/null +++ b/stdlib/src/builtin/bin.mojo @@ -0,0 +1,81 @@ +# ===----------------------------------------------------------------------=== # +# Copyright (c) 2024, Modular Inc. All rights reserved. +# +# Licensed under the Apache License v2.0 with LLVM Exceptions: +# https://llvm.org/LICENSE.txt +# +# 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. +# ===----------------------------------------------------------------------=== # +"""Implements the `bin()` function + +These are Mojo built-ins, so you don't need to import them. +""" + + +@always_inline("nodebug") +fn bin(b: Scalar[DType.bool]) -> String: + """Returns the binary representation of a scalar bool. + + Args: + b: A scalar bool value. + + Returns: + The binary string representation of b. + """ + return bin(int(b)) + + +fn bin[type: DType](num: Scalar[type]) -> String: + """Return the binary string representation an integral value. + + ```mojo + print(bin(123)) + print(bin(-123)) + ``` + ```plaintext + '0b1111011' + '-0b1111011' + ``` + + Parameters: + type: The data type of the integral scalar. + + Args: + num: An integral scalar value. + + Returns: + The binary string representation of num. + """ + constrained[type.is_integral(), "Expected integral value"]() + alias BIN_PREFIX = "0b" + + if num == 0: + return BIN_PREFIX + "0" + + # TODD: pre-allocate string size when #2194 is resolved + var result = String() + var cpy = abs(num) + while cpy > 0: + result += str(cpy & 1) + cpy = cpy >> 1 + + result = BIN_PREFIX + result[::-1] + return "-" + result if num < 0 else result + + +@always_inline("nodebug") +fn bin(num: Int) -> String: + """Returns the binary representation of an Int. + + Args: + num: An Int value. + + Returns: + The binary string representation of num. + """ + # TODO: Should accept any type that implements the __index__ method according to Python + return bin(Scalar[DType.index](num)) diff --git a/stdlib/test/builtin/test_bin.mojo b/stdlib/test/builtin/test_bin.mojo new file mode 100644 index 000000000..f9aa29b77 --- /dev/null +++ b/stdlib/test/builtin/test_bin.mojo @@ -0,0 +1,44 @@ +# ===----------------------------------------------------------------------=== # +# Copyright (c) 2024, Modular Inc. All rights reserved. +# +# Licensed under the Apache License v2.0 with LLVM Exceptions: +# https://llvm.org/LICENSE.txt +# +# 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. +# ===----------------------------------------------------------------------=== # +# RUN: %mojo %s + +from testing import assert_equal + + +def test_bin_scalar(): + assert_equal(bin(Int8(2)), "0b10") + assert_equal(bin(Int32(123)), "0b1111011") + assert_equal(bin(Int32(-123)), "-0b1111011") + assert_equal(bin(Scalar[DType.bool](True)), "0b1") + assert_equal(bin(Scalar[DType.bool](False)), "0b0") + + +def test_bin_int(): + assert_equal(bin(0), "0b0") + assert_equal(bin(1), "0b1") + assert_equal(bin(-1), "-0b1") + assert_equal(bin(4), "0b100") + assert_equal(bin(Int(-4)), "-0b100") + assert_equal(bin(389703), "0b1011111001001000111") + assert_equal(bin(-10), "-0b1010") + + +def test_bin_bool(): + assert_equal(bin(True), "0b1") + assert_equal(bin(False), "0b0") + + +def main(): + test_bin_scalar() + test_bin_int() + test_bin_bool()