Skip to content

Commit

Permalink
add direct support for more integer types in iround. fixes #7441
Browse files Browse the repository at this point in the history
also add more Float16 -> Integer conversions
  • Loading branch information
JeffBezanson committed Jun 30, 2014
1 parent 903b701 commit a2313ce
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 44 deletions.
39 changes: 17 additions & 22 deletions base/float.jl
Original file line number Diff line number Diff line change
Expand Up @@ -70,33 +70,28 @@ iround{T<:Integer}(::Type{T}, x::FloatingPoint) = convert(T,round(x))

## fast specific type conversions ##

if WORD_SIZE == 64
iround(x::Float32) = iround(float64(x))
itrunc(x::Float32) = box(Int64,fptosi(Int64,unbox(Float32,x)))
iround(x::Float64) = box(Int64,fpsiround(unbox(Float64,x)))
itrunc(x::Float64) = box(Int64,fptosi(unbox(Float64,x)))
else
iround(x::Float32) = box(Int32,fpsiround(unbox(Float32,x)))
itrunc(x::Float32) = box(Int32,fptosi(unbox(Float32,x)))
iround(x::Float64) = int32(box(Int64,fpsiround(unbox(Float64,x))))
itrunc(x::Float64) = int32(box(Int64,fptosi(unbox(Float64,x))))
end
iround(x::Float32) = iround(Int, x)
iround(x::Float64) = iround(Int, x)
itrunc(x::Float32) = itrunc(Int, x)
itrunc(x::Float64) = itrunc(Int, x)

for to in (Int8, Uint8, Int16, Uint16)
for to in (Int8, Int16, Int32, Int64)
@eval begin
iround(::Type{$to}, x::Float32) = box($to,trunc_int($to,fpsiround(unbox(Float32,x))))
iround(::Type{$to}, x::Float64) = box($to,trunc_int($to,fpsiround(unbox(Float64,x))))
iround(::Type{$to}, x::Float32) = box($to,fpsiround($to,unbox(Float32,x)))
iround(::Type{$to}, x::Float64) = box($to,fpsiround($to,unbox(Float64,x)))
itrunc(::Type{$to}, x::Float32) = box($to,fptosi($to,unbox(Float32,x)))
itrunc(::Type{$to}, x::Float64) = box($to,fptosi($to,unbox(Float64,x)))
end
end

iround(::Type{Int32}, x::Float32) = box(Int32,fpsiround(unbox(Float32,x)))
iround(::Type{Int32}, x::Float64) = box(Int32,trunc_int(Int32,fpsiround(unbox(Float64,x))))
iround(::Type{Uint32}, x::Float32) = box(Uint32,fpuiround(unbox(Float32,x)))
iround(::Type{Uint32}, x::Float64) = box(Uint32,trunc_int(Uint32,fpuiround(unbox(Float64,x))))
iround(::Type{Int64}, x::Float32) = box(Int64,fpsiround(float64(x)))
iround(::Type{Int64}, x::Float64) = box(Int64,fpsiround(unbox(Float64,x)))
iround(::Type{Uint64}, x::Float32) = box(Uint64,fpuiround(float64(x)))
iround(::Type{Uint64}, x::Float64) = box(Uint64,fpuiround(unbox(Float64,x)))
for to in (Uint8, Uint16, Uint32, Uint64)
@eval begin
iround(::Type{$to}, x::Float32) = box($to,fpuiround($to,unbox(Float32,x)))
iround(::Type{$to}, x::Float64) = box($to,fpuiround($to,unbox(Float64,x)))
itrunc(::Type{$to}, x::Float32) = box($to,fptoui($to,unbox(Float32,x)))
itrunc(::Type{$to}, x::Float64) = box($to,fptoui($to,unbox(Float64,x)))
end
end

iround(::Type{Int128}, x::Float32) = convert(Int128,round(x))
iround(::Type{Int128}, x::Float64) = convert(Int128,round(x))
Expand Down
9 changes: 8 additions & 1 deletion base/float16.jl
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,14 @@ function convert(::Type{Float16}, val::Float32)
reinterpret(Float16, h)
end

convert(::Type{Integer}, x::Float16) = convert(Int,float32(x))
convert(::Type{Bool}, x::Float16) = (x!=0)
convert(::Type{Int128}, x::Float16) = convert(Int128, float32(x))
convert(::Type{Uint128}, x::Float16) = convert(Uint128, float32(x))

convert{T<:Integer}(::Type{T}, x::Float16) = convert(T, float32(x))

iround{T<:Integer}(::Type{T}, x::Float16) = iround(T, float32(x))
itrunc{T<:Integer}(::Type{T}, x::Float16) = itrunc(T, float32(x))

round(x::Float16) = float16(round(float32(x)))
trunc(x::Float16) = float16(trunc(float32(x)))
Expand Down
1 change: 1 addition & 0 deletions base/gmp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ function BigInt(x::Integer)
end

convert(::Type{BigInt}, x::Integer) = BigInt(x)
convert(::Type{BigInt}, x::Float16) = BigInt(x)
convert(::Type{BigInt}, x::FloatingPoint) = BigInt(x)

function convert(::Type{Int64}, x::BigInt)
Expand Down
11 changes: 4 additions & 7 deletions base/int.jl
Original file line number Diff line number Diff line change
Expand Up @@ -503,14 +503,11 @@ widen(::Type{Uint64}) = Uint128

# requires int arithmetic defined, for the loops to work

for f in (:int, :int8, :int16, :int32, :signed, :integer)
@eval ($f)(x::FloatingPoint) = ($f)(iround(x))
end

for (f,t) in ((:uint8,:Uint8), (:uint16,:Uint16), (:uint32,:Uint32),
(:int64,:Int64), (:uint64,:Uint64),
for (f,t) in ((:uint8,:Uint8), (:uint16,:Uint16), (:uint32,:Uint32), (:uint64,:Uint64),
(:int8,:Int8), (:int16,:Int16), (:int32,:Int32), (:int64,:Int64),
(:int128,:Int128), (:uint128,:Uint128),
(:unsigned,:Uint), (:uint,:Uint))
(:signed,:Int), (:unsigned,:Uint), (:integer,:Int),
(:int,:Int), (:uint,:Uint))
@eval ($f)(x::FloatingPoint) = iround($t,x)
end

Expand Down
72 changes: 58 additions & 14 deletions src/intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -551,13 +551,14 @@ static Value *emit_checked_fptoui(jl_value_t *targ, Value *x, jl_codectx_t *ctx)
return emit_checked_fptoui(staticeval_bitstype(targ, "checked_fptoui", ctx), x, ctx);
}

static Value *emit_iround(Value *x, bool issigned, jl_codectx_t *ctx)
static Value *emit_iround(Type *to, Value *x, bool issigned, jl_codectx_t *ctx)
{
int nmantissa, expoffs, expbits;
int64_t topbit;
Type *intt, *floatt;
Value *bits = JL_INT(x);
Value *max, *min;
int tobits = to->getPrimitiveSizeInBits();

if (bits->getType()->getPrimitiveSizeInBits() == 32) {
nmantissa = 23;
Expand All @@ -566,11 +567,28 @@ static Value *emit_iround(Value *x, bool issigned, jl_codectx_t *ctx)
topbit = BIT31;
intt = T_int32; floatt = T_float32;
if (issigned) {
max = ConstantFP::get(floatt, 2.1474835e9);
min = ConstantFP::get(floatt, -2.1474836e9);
switch (tobits) {
case 8: max = ConstantFP::get(floatt, 127.99999);
min = ConstantFP::get(floatt, -128.99998); break;
case 16: max = ConstantFP::get(floatt, 32767.998);
min = ConstantFP::get(floatt, -32768.996); break;
case 32: max = ConstantFP::get(floatt, 2.1474835e9);
min = ConstantFP::get(floatt, -2.1474836e9); break;
case 64: max = ConstantFP::get(floatt, 9.2233715e18);
min = ConstantFP::get(floatt, -9.223372e18); break;
default:
jl_error("unsupported type in fpsiround");
}
}
else {
max = ConstantFP::get(floatt, 4.294967e9);
switch (tobits) {
case 8: max = ConstantFP::get(floatt, 255.99998); break;
case 16: max = ConstantFP::get(floatt, 65535.996); break;
case 32: max = ConstantFP::get(floatt, 4.294967e9); break;
case 64: max = ConstantFP::get(floatt, 1.8446743e19); break;
default:
jl_error("unsupported type in fpuiround");
}
// most negative number that truncates to zero
min = ConstantFP::get(floatt, -0.99999994);
}
Expand All @@ -582,11 +600,28 @@ static Value *emit_iround(Value *x, bool issigned, jl_codectx_t *ctx)
topbit = BIT63;
intt = T_int64; floatt = T_float64;
if (issigned) {
max = ConstantFP::get(floatt, 9.223372036854775e18);
min = ConstantFP::get(floatt, -9.223372036854776e18);
switch (tobits) {
case 8: max = ConstantFP::get(floatt, 127.99999999999999);
min = ConstantFP::get(floatt, -128.99999999999997); break;
case 16: max = ConstantFP::get(floatt, 32767.999999999996);
min = ConstantFP::get(floatt, -32768.99999999999); break;
case 32: max = ConstantFP::get(floatt, 2.1474836479999998e9);
min = ConstantFP::get(floatt, -2.1474836489999995e9); break;
case 64: max = ConstantFP::get(floatt, 9.223372036854775e18);
min = ConstantFP::get(floatt, -9.223372036854776e18); break;
default:
jl_error("unsupported type in fpsiround");
}
}
else {
max = ConstantFP::get(floatt, 1.844674407370955e19);
switch (tobits) {
case 8: max = ConstantFP::get(floatt, 255.99999999999997); break;
case 16: max = ConstantFP::get(floatt, 65535.99999999999); break;
case 32: max = ConstantFP::get(floatt, 4.2949672959999995e9); break;
case 64: max = ConstantFP::get(floatt, 1.844674407370955e19); break;
default:
jl_error("unsupported type in fpuiround");
}
min = ConstantFP::get(floatt, -0.9999999999999999);
}
}
Expand Down Expand Up @@ -620,9 +655,9 @@ static Value *emit_iround(Value *x, bool issigned, jl_codectx_t *ctx)
builder.CreateFCmpOGE(src, min)),
prepare_global(jlinexacterr_var), ctx);
if (issigned)
return builder.CreateFPToSI(src, intt);
return builder.CreateFPToSI(src, to);
else
return builder.CreateFPToUI(src, intt);
return builder.CreateFPToUI(src, to);
}

static Value *emit_pointerref(jl_value_t *e, jl_value_t *i, jl_codectx_t *ctx)
Expand Down Expand Up @@ -826,6 +861,20 @@ static Value *emit_intrinsic(intrinsic f, jl_value_t **args, size_t nargs,
jl_error("fptosi: wrong number of arguments");
}

case fpsiround:
case fpuiround:
if (nargs == 1) {
Value *x = FP(auto_unbox(args[1], ctx));
return emit_iround(JL_INTT(x->getType()), x, f == fpsiround, ctx);
}
else if (nargs == 2) {
return emit_iround(Type::getIntNTy(jl_LLVMContext, try_to_determine_bitstype_nbits(args[1],ctx)),
FP(auto_unbox(args[2],ctx)), f == fpsiround, ctx);
}
else {
jl_errorf("%s: wrong number of arguments", f == fpsiround ? "fpsiround" : "fpuiround");
}

HANDLE(fptrunc,2) return builder.CreateFPTrunc(FP(auto_unbox(args[2],ctx)), FTnbits(try_to_determine_bitstype_nbits(args[1],ctx)));
HANDLE(fpext,2) {
// when extending a float32 to a float64, we need to force
Expand Down Expand Up @@ -1205,11 +1254,6 @@ static Value *emit_intrinsic(intrinsic f, jl_value_t **args, size_t nargs,
}
#endif

HANDLE(fpsiround,1)
HANDLE(fpuiround,1)
{
return emit_iround(x, f == fpsiround, ctx);
}
HANDLE(nan_dom_err,2) {
// nan_dom_err(f, x) throw DomainError if isnan(f)&&!isnan(x)
Value *f = FP(x); x = FP(y);
Expand Down
9 changes: 9 additions & 0 deletions test/numbers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1782,3 +1782,12 @@ end
@test [1,2,3] .// [4,5,6] == [1//4, 2//5, 3//6]
@test [1+2im,3+4im] .// [5,6] == [(1+2im)//5,(3+4im)//6]
@test [1//3+2im,3+4im] .// [5,6] == [(1//3+2im)//5,(3+4im)//6]

# issue #7441
@test_throws InexactError int32(2.0^50)

@test_throws InexactError iround(Uint8, 255.5)
@test iround(Uint8, 255.4) === 0xff

@test_throws InexactError iround(Int16, -32768.7)
@test iround(Int16, -32768.1) === int16(-32768)

0 comments on commit a2313ce

Please sign in to comment.