Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

InexactError: Int64 even when checking divisibility

Tags:

julia

Im having problems with dividing large numbers. I have a while loop that divides the number if the index is within the array limits and if its remainder is zero:

        while ((i + j*arr[i]) <= lim && arr[i + j*arr[i]] % arr[i] == 0)
            arr[i + j*arr[i]] /= arr[i]
        end

Im using an array of Int64 on max value of arr[i]<(150*10^6)^2, even changing to Int128 doesnt help, BigInt is out of the question because it takes too much time. I dont understand why I get Inexact error inside the loop if it enters only if the remainder is zero. and typemax(Int64)>max(arr) here is the full error:

InexactError: Int64(1.8014400929875968e15)
in top-level scope at P-146-Investigating a Prime Pattern:51
in test at P-146-Investigating a Prime Pattern:39
in setindex! at base\array.jl:826 
in convert at base\number.jl:7 
in Int64 at base\float.jl:710 

it seems to happen only after the value in the array is above (90*10^6)^2

like image 535
Alex Zh Avatar asked Jul 23 '20 14:07

Alex Zh


2 Answers

TLDR: use ÷.

Dividing integers with the / function in Julia returns floating point numbers. Importantly, it promotes integers to floating point numbers before it does the division. For example, the number 10^16-1 is obviously divisible by three:

julia> 9999999999999999 % 3
0

However, if we try to do this division with /, we don't get the correct answer:

julia> 9999999999999999 / 3
3.3333333333333335e15

julia> using Printf

julia> @printf "%f" 9999999999999999 / 3
3333333333333333.500000

So of course, trying to store the above number in an integer array is going to throw an inexact error. But why is this? Well you're above maxintfloat(Float64). Since floating point numbers have ~15 decimal digits of precision, above this value they are no longer able to exactly represent every single integer. They start skipping (and rounding!) them. Thus you're not really dividing 10^16-1 by three, you're dividing 10^16 by three!

julia> 10^16-1
9999999999999999

julia> Float64(10^16-1)
1.0e16

Much better to use ÷ (that is, div) — not only will it handle these cases without worrying about floating point precision, but it'll also keep things as integers:

julia> 9999999999999999 ÷ 3
3333333333333333
like image 175
mbauman Avatar answered Nov 07 '22 23:11

mbauman


Problem is that / operation produces float, so following = tries to assign float value to an element of the array which is of the Int type. Consider this example

> a = [11]
> b = [2]
> a[1] /= b[1]
ERROR: InexactError: Int64(5.5)
Stacktrace:
 [1] Int64 at ./float.jl:710 [inlined]
 [2] convert at ./number.jl:7 [inlined]
 [3] setindex!(::Array{Int64,1}, ::Float64, ::Int64) at ./array.jl:849
 [4] top-level scope at REPL[6]:1

So it tries to assign 5.5 to the element of the array which consists of Int.

You can do one of the following, depending on your task

  1. One way or another declare arrays as arrays of float
> a = [11.0]
1-element Array{Float64,1}:
 11.0
> b = [2.0]
> a[1] /= b[1]
5.5
  1. Use integer division (div or equivalently ÷) to make a division
> a = [11]
> b = [2]
> a[1] ÷= b[1]
5

As for your original question, why it produces this error, I think that since you have rather big numbers, after converting to float and the following division you get an inexact result, which cannot be converted back to Int.

like image 24
Andrej Oskin Avatar answered Nov 08 '22 00:11

Andrej Oskin