modularml / mojo

The Mojo Programming Language
https://docs.modular.com/mojo/manual/
Other
23.38k stars 2.6k forks source link

[BETA]: UInt64 unexpectedly truncates #556

Closed lsh closed 1 year ago

lsh commented 1 year ago

Bug description

UInt64 values do not print the expected value.

Steps to reproduce

fn main():
    let ui64x4 = SIMD[DType.uint64, 4](
        0xA0761D6478BD642F,
        0xE7037ED1A0B428DB,
        0x8EBC6AF09C88C6E3,
        0x589965CC75374CC3,
    )
    print(ui64x4)

# outputs
[11562461410679940143, 166462880865

Expected:

[11562461410679940143, 16646288086500911323, 10285213230658275043, 6384245875588680899]

System information

- What OS did you do install modular CLI/mojo on ? Ubuntu 22.04
- Provide version information for Mojo by pasting the output of `mojo -v`
mojo 0.2.0 (4c0ef274)
- Provide Modular CLI version by pasting the output of `modular -v`
modular 0.1.2
rd4com commented 1 year ago

@lsh @Mogball Hello, i've seen this issue on the discord, decided to try to contribute, i dont know if users are supposed to try to help in the issues? i am new to github and came just because Mojo is awesome

fn print_replicate[size:Int](arg: SIMD[DType.uint64, size]) raises:
    var newstring: String = "["
    for i in range(len(arg)):
        newstring+=(String(UInt64(arg[i])))     #this is the problem
    newstring += "]"

    #print(atol("166462880865"))                #<- no problem here 
    #print(atol("10285213230658275043"))        #<- no problem here
    #print(atol(String(arg[0])))                 #<- problem here !!! Unhandled exception caught during execution: String is not convertible to integer.
    #print(atol(String(arg[1])))                 #<- problem here !!! Unhandled exception caught during execution: String expresses an integer too large to store in Int.

    print(newstring)

fn main() raises:
    let ui64 = SIMD[DType.uint64, 2](
        0xE7037ED1A0B428DB,
        0x8EBC6AF09C88C6E3
    )

    print(ui64)                             #[166462880865 <----- the bug reported

    print(ui64[0])                          #166462880865
    print(ui64[1])                          #10285213230658275043
    print(0xE7037ED1A0B428DB)               #-1800455987208640293
    print(0x8EBC6AF09C88C6E3)               #-8161530843051276573

    print(UInt64(0xE7037ED1A0B428DB))       #166462880865
    print(UInt64(0x8EBC6AF09C88C6E3))       #10285213230658275043

    var result:String = String(ui64)
    print(result)                           #[166462880865 <----- the bug reported
    print(len(result))                      #44 characters, this is not good but promising

    print("----------------- printed character per character")
    for i in range(len(result)):
        print_no_newline(result[i])  
                                            #character 14 seem to be the problem

                                            #[166462880865, 10285213230658275043]   fantastic <--------------- ok

    print("\n----------------- function replicate the issue")
    print_replicate[2](ui64)                #[166462880865 

    #note that printing character by character is fine,
    #Issue because it print an escape or null character? 

    #[166462880865, 10285213230658275043] is 36 characters and not 44 like above in len(result)

    var final_string = "[166462880865, 10285213230658275043]"
    print(len(final_string))
    print(final_string)                             #does print right
lsh commented 1 year ago

@rd4com I'm not sure I completely understand what this script does. 0xE7037ED1A0B428DB should print as 16646288086500911323, not 166462880865 (as in your final string).

rd4com commented 1 year ago

Yes, sorry it is a mistake, maybe this example is better:

def main():
fn main():
    var tmp:UInt64 = 16646288086500911323
    var a:String = String(tmp)
    print(a)                        #prints 166462880865         wich is 12 characters
    print(len(a))                   #20 characters

    for i in range(len(a)):
        print_no_newline(ord(a[i]))       #premature null termination on position 13
        print_no_newline("-")

The storage of the uin64 is correct of course:

from math.limit import max_finite
def main():
    print(~UInt64(0))                   #184467440737095516
    print(~SIMD[DType.uint64,1](0))     #184467440737095516
    print(max_finite[DType.uint64]())   #184467440737095516
                                        #18446744073709551615 max u64 value

    let tmp = Pointer[UInt8]().alloc(8)

    var correct = 0
    for i in range(8):
        tmp.store(i,255)
        if tmp.load(i) == 255:
            correct +=1

    if correct == 8:
        print("all correct")            #all correct

    let convert = tmp.bitcast[UInt64]()
    let final:UInt64 = convert.load(0)
    print(final)                        #184467440737095516

    convert.store(0,18446744073709551615)

    let bytes = convert.bitcast[UInt8]()
    correct = 0
    for i in range(8):
        if bytes.load(i) == 255:
            correct +=1

    if correct == 8:
        print("all correct")            #all correct        

    let ptr = Pointer[UInt64]().alloc(1)
    ptr.store(0,18446744073709551615)
    print(ptr.load(0))                  #184467440737095516

    let ptr_bytes = ptr.bitcast[UInt8]()
    correct = 0
    for i in range(8):
        if ptr_bytes.load(i) == 255:
            correct +=1

    if correct == 8:
        print("all correct")            #all correct