如何打印无符号的64位整数

问题描述

我正在kattis上处理此smallest multiple problem

我已经用Python和C ++解决了它,但是现在我想做OCaml。

这是我的代码

open Printf;;

let rec gcd (a : int64) (b : int64) : int64 =
    if not (Int64.unsigned_compare b 0L > 0) then
        a
    else
        gcd b (Int64.unsigned_rem a b);;

try
    while true;
    do
        let line = read_line ()
        in
        if String.length line > 0 then
            let (nums : int64 list) = List.map (fun (s:string) : (int64) ->
                (Int64.of_string (Char.escaped '0' ^ Char.escaped 'u' ^ s ))) (String.split_on_char ' ' line)
            in
            let rec reduce (li : int64 list) (init : int64) : (int64) =
                match li with
                | [] -> init
                | head :: tail -> reduce tail ( Int64.unsigned_div (Int64.mul head init) (gcd head init) ) 
            in
            print_string ( Int64.to_string (reduce nums 1L) ^ "\n")
        else
            raise End_of_file
    done;
with End_of_file -> ();;

我可以通过第一个案例,但是第二个(也是最后一个)案例会导致错误的答案。这很奇怪,因为我的前两份不同语言的论文中我的逻辑是相同的。

我的猜测是我错误地打印了无符号的64位整数:

print_string ( Int64.to_string (reduce nums 1L) ^ "\n")

之前,我尝试过:

printf "%Lu\n" (reduce nums 1L)

但是Printf documentation

u,n,l,L,or N: convert an integer argument to unsigned decimal. Warning: n,and N are used for scanf,and should not be used for printf. 

我实际上并不认为此警告与我的情况有关,但我仍然感到疲倦。

有什么想法吗?感谢您的阅读!

解决方法

您的代码对我有用。您可以考虑从头开始重新启动OCaml,然后复制/粘贴上面的代码。那就是我所做的,对我有用。

. . .
  with End_of_file -> ();;
2 3 5
30
1 2 3 4
12
399 772 163 959 242
832307365428

- : unit = ()
# 

我有一个64位系统,物有所值。即max_int对我来说是4611686018427387903。

,

466941151233371166不是任何输入的倍数,因此显然是错误的。输入数字相当大,所以我猜您只是整数溢出。另一方面,您的C ++代码说1,这也不是任何数字的倍数,而且显然也是错误的。

我看到一个可能是问题的地方

( Int64.unsigned_div (Int64.mul head init) (gcd head init) )

在处理输入时,init越来越大,然后将其乘以下一个数字。仅在将其除以GCD之后。在该步骤中,它暂时超过了64位,您会丢失一些位。

根据GCD的定义,head和init都可以被它整除。那么,为什么不将其中之一乘以GCD呢?

(Int64.mul init (Int64.unsigned_div head (gcd head init)))

这样,您的中间数永远不会比结果大,并且接近64位限制的结果仍然会产生正确的结果。