Laurent

You can use a construct such as

```Julia
immutable FastInt
    isbig::Bool
    small::Int
    big::BigInt
    FastInt(x::Int) = new(false, x)
    FastInt(x::BigInt) = new(true, 0, x)
end
getbig(x::FastInt) = x.isbig ? x.big : BigInt(x.small)
function add(x::FastInt, y::FastInt)
    if !isbig(x) & !isbig(y)
        # add overflow checking
        return FastInt(x.small + y.small)
    end
    FastInt(getbig(x) + getbig(y))
end
```

This will be reasonably efficient (apart from memory usage), and since
unused `BigInt` objects are never initialized, no memory will be
allocated for them.

You could also fold the `isbig` field into `small` by e.g. choosing to
use `typemin(Int)` as a value that indicates that the `BigInt` field
should be used.

-erik



On Sat, Apr 9, 2016 at 8:07 AM, Laurent Bartholdi
<laurent.bartho...@gmail.com> wrote:
> Thanks for the explanations. Am I correct in understanding that objects are
> garbage-collected when they're only pointed to, and this causes the problem?
> This kills my naive idea of using pointers to BigInts as a 64-bit datatype
> compatible with ints, and is suggested by the following experiment:
>
> julia> l = [pointer_from_objref(BigInt(i)) for i=1:10]
> 10-element Array{Ptr{Void},1}:
>  Ptr{Void} @0x0000000118c77150
>  Ptr{Void} @0x0000000118c77170
>  Ptr{Void} @0x0000000118c77190
>  Ptr{Void} @0x0000000118c771b0
>  Ptr{Void} @0x0000000118c771d0
>  Ptr{Void} @0x0000000118c771f0
>  Ptr{Void} @0x0000000118c77210
>  Ptr{Void} @0x0000000118c77230
>  Ptr{Void} @0x0000000118c77250
>  Ptr{Void} @0x0000000118c77270
>
>
> julia> unsafe_pointer_to_objref(l[7])
> 7
>
>
> julia> map(unsafe_pointer_to_objref,l)
> Segmentation fault: 11
>
>
> On Friday, 8 April 2016 17:47:34 UTC+2, Stefan Karpinski wrote:
>>
>> This could help if both parts of the union were plain old data like Int64
>> and Float64, but in the case of Int and BigInt, one of them is a more
>> complex type, which would currently force the whole thing to be boxed and
>> live in the heap anyway. What's needed here is the ability to stack-allocate
>> objects that refer to the heap. We cannot do that now, but it is an
>> important planned CG improvement.
>>
>> On Fri, Apr 8, 2016 at 11:28 AM, Scott Jones <scott.pa...@gmail.com>
>> wrote:
>>>
>>> I like very much the idea of a discriminated union - that would help
>>> enormously with some of the stuff I work on.
>>>
>>>
>>> On Friday, April 8, 2016 at 8:47:59 AM UTC-4, Erik Schnetter wrote:
>>>>
>>>> Laurent
>>>>
>>>> I'm afraid you can't use `reinterpret` with a type such as `BigInt`.
>>>>
>>>> I think what you want is an extension of `Nullable`: A nullable type
>>>> represents an object of a particular type that might or might not be
>>>> there; there's hope that this would be done efficiently, e.g. via an
>>>> additional bit. What you want is an efficient representation of a
>>>> discriminated union -- a type that can represent either of two types,
>>>> but without the overhead from boxing the types as is currently done in
>>>> a `Union`. Unfortunately, Julia currently doesn't provide this, but it
>>>> would make sense to have a feature request for this.
>>>>
>>>> This might look like this:
>>>> ```Julia
>>>> immutable FastInt
>>>>     val::DiscriminatedUnion{Int, BigInt}
>>>> end
>>>> function (+)(a::FastInt, b::FastInt)
>>>>     if typeindex(a.val) == 1 & typeindex(b.val) == 1
>>>>         ov,res = add_with_overflow(a.val[1], b.val[1])
>>>>         ov && return FastInt(BigInt(res))
>>>>         return FastInt(res)
>>>>     end
>>>>     # TODO: handle mixed case
>>>>     FastInt(a.val[2] + b.val[2])
>>>> end
>>>> ```
>>>>
>>>> This would be the same idea as yours, but the `reinterpret` occurs
>>>> within Julia, in a type-safe and type-stable manner, in a way such
>>>> that the compiler can optimize better.
>>>>
>>>> You could try defining a type that contains two fields, both an `Int`
>>>> and a `BigInt` -- maybe `BigInt` will handle the case of a value that
>>>> is never used in a more efficient manner that doesn't require
>>>> allocating an object.
>>>>
>>>> -erik
>>>>
>>>> On Fri, Apr 8, 2016 at 2:07 AM, Laurent Bartholdi
>>>> <laurent....@gmail.com> wrote:
>>>> > Dear all,
>>>> > How hard would it be to code arbitrary-precision integers in Julia
>>>> > with at
>>>> > worst 2x performance loss over native Ints?
>>>> >
>>>> > This is what I have in mind: have a bitstype structure, say 64 bits,
>>>> > which
>>>> > is either the address of a BigInt (if even), or an Int64 (if odd).
>>>> > Addition
>>>> > would be something like:
>>>> >
>>>> > function +(a::FastInt,b::FastInt)
>>>> >     if a&b&1
>>>> >         (result,obit) = @llvm.sadd.with.overflow.i64(a,b&~1)
>>>> >         obit ? reinterpret(FastInt,BigInt(a>>1)+(b>>1)) : result
>>>> >     elseif a&1
>>>> >         reinterpret(FastInt,(a>>1) + reinterpret(BigInt,b))
>>>> >     elseif b&1
>>>> >         reinterpret(FastInt,reinterpret(BigInt,a) + b>>1)
>>>> >     else
>>>> >         reinterpret(FastInt,reinterpret(BigInt,a) +
>>>> > reinterpret(BigInt,b))
>>>> >     end
>>>> > end
>>>> >
>>>> > (code not meant to be run, just a skeleton)
>>>> >
>>>> > This would be very useful in the development of computer algebra
>>>> > systems, in
>>>> > which BigInts are too slow and eat up too much memory, but one is
>>>> > ready to
>>>> > pay a small price for guard against arithmetic overflows.
>>>> >
>>>> > If this is too complicated, then perhaps at least a type of integers
>>>> > that
>>>> > would raise an error in case of over/underflows? Those could be caught
>>>> > in
>>>> > throw/catch enclosures, so the user could restart the operation with
>>>> > BigInts.
>>>> >
>>>> > TIA, Laurent
>>>>
>>>>
>>>>
>>>> --
>>>> Erik Schnetter <schn...@gmail.com>
>>>> http://www.perimeterinstitute.ca/personal/eschnetter/
>>
>>
>



-- 
Erik Schnetter <schnet...@gmail.com>
http://www.perimeterinstitute.ca/personal/eschnetter/

Reply via email to