///|
fn round_inexact_context(context : Context, exact : Bool) -> Context {
if exact {
context.raise_flags(ExceptionFlags::inexact())
} else {
context
}
}
///|
fn round_invalid_context(context : Context) -> Context {
context.raise_flags(ExceptionFlags::invalid())
}
///|
fn round_to_ui32_invalid(context : Context, sign : Bool) -> SoftResult[UInt32] {
let value = if sign {
ui32_from_neg_overflow(context.specialization)
} else {
ui32_from_pos_overflow(context.specialization)
}
{ value, context: round_invalid_context(context), }
}
///|
/// Ports `softfloat_roundToUI32` from `s_roundToUI32.c`.
fn round_to_ui32(
context : Context,
sign : Bool,
sig : UInt64,
rounding : RoundingMode,
exact : Bool,
) -> SoftResult[UInt32] {
let round_increment = match rounding {
NearEven | NearMaxMag => 0x800UL
Max if !sign => 0xFFFUL
_ => 0UL
}
if sign && sig != 0UL && (rounding == Min || rounding == Odd) {
round_to_ui32_invalid(context, sign)
} else {
let round_bits = sig & 0xFFFUL
let sig = sig + round_increment
if (sig & 0xFFFFF00000000000UL) != 0UL {
round_to_ui32_invalid(context, sign)
} else {
let mut value = (sig >> 12).to_uint()
if round_bits == 0x800UL && rounding == NearEven {
value = value & 0xFFFFFFFEU
}
if sign && value != 0U {
round_to_ui32_invalid(context, sign)
} else if round_bits != 0UL {
if rounding == Odd {
value = value | 1U
}
{ value, context: round_inexact_context(context, exact), }
} else {
{ value, context, }
}
}
}
}
///|
fn round_to_ui64_invalid(context : Context, sign : Bool) -> SoftResult[UInt64] {
let value = if sign {
ui64_from_neg_overflow(context.specialization)
} else {
ui64_from_pos_overflow(context.specialization)
}
{ value, context: round_invalid_context(context), }
}
///|
/// Ports `softfloat_roundToUI64` from `s_roundToUI64.c`.
fn round_to_ui64(
context : Context,
sign : Bool,
sig : UInt64,
sig_extra : UInt64,
rounding : RoundingMode,
exact : Bool,
) -> SoftResult[UInt64] {
if sign && (sig | sig_extra) != 0UL && (rounding == Min || rounding == Odd) {
round_to_ui64_invalid(context, sign)
} else {
let increment = match rounding {
NearEven | NearMaxMag => sig_extra >= 0x8000000000000000UL
Max if !sign => sig_extra != 0UL
_ => false
}
let incremented = if increment { sig + 1UL } else { sig }
if increment && incremented == 0UL {
round_to_ui64_invalid(context, sign)
} else {
let mut value = incremented
if increment && sig_extra == 0x8000000000000000UL && rounding == NearEven {
value = value & 0xFFFFFFFFFFFFFFFEUL
}
if sign && value != 0UL {
round_to_ui64_invalid(context, sign)
} else if sig_extra != 0UL {
if rounding == Odd {
value = value | 1UL
}
{ value, context: round_inexact_context(context, exact), }
} else {
{ value, context, }
}
}
}
}
///|
fn round_to_i32_invalid(context : Context, sign : Bool) -> SoftResult[Int32] {
let value = if sign {
i32_from_neg_overflow(context.specialization)
} else {
i32_from_pos_overflow(context.specialization)
}
{ value, context: round_invalid_context(context), }
}
///|
/// Ports `softfloat_roundToI32` from `s_roundToI32.c`.
fn round_to_i32(
context : Context,
sign : Bool,
sig : UInt64,
rounding : RoundingMode,
exact : Bool,
) -> SoftResult[Int32] {
let round_increment = match rounding {
NearEven | NearMaxMag => 0x800UL
Min if sign => 0xFFFUL
Odd if sign => 0xFFFUL
Max if !sign => 0xFFFUL
_ => 0UL
}
let round_bits = sig & 0xFFFUL
let sig = sig + round_increment
if (sig & 0xFFFFF00000000000UL) != 0UL {
round_to_i32_invalid(context, sign)
} else {
let mut sig32 = (sig >> 12).to_uint()
if round_bits == 0x800UL && rounding == NearEven {
sig32 = sig32 & 0xFFFFFFFEU
}
let value_bits = if sign { 0U - sig32 } else { sig32 }
let mut value = value_bits.reinterpret_as_int()
if value != 0 && (value < 0) != sign {
round_to_i32_invalid(context, sign)
} else if round_bits != 0UL {
if rounding == Odd {
value = value | 1
}
{ value, context: round_inexact_context(context, exact), }
} else {
{ value, context, }
}
}
}
///|
fn round_to_i64_invalid(context : Context, sign : Bool) -> SoftResult[Int64] {
let value = if sign {
i64_from_neg_overflow(context.specialization)
} else {
i64_from_pos_overflow(context.specialization)
}
{ value, context: round_invalid_context(context), }
}
///|
/// Ports `softfloat_roundToI64` from `s_roundToI64.c`.
fn round_to_i64(
context : Context,
sign : Bool,
sig : UInt64,
sig_extra : UInt64,
rounding : RoundingMode,
exact : Bool,
) -> SoftResult[Int64] {
let increment = match rounding {
NearEven | NearMaxMag => sig_extra >= 0x8000000000000000UL
Min if sign => sig_extra != 0UL
Odd if sign => sig_extra != 0UL
Max if !sign => sig_extra != 0UL
_ => false
}
let incremented = if increment { sig + 1UL } else { sig }
if increment && incremented == 0UL {
round_to_i64_invalid(context, sign)
} else {
let mut value_bits = if sign { 0UL - incremented } else { incremented }
if increment && sig_extra == 0x8000000000000000UL && rounding == NearEven {
value_bits = value_bits & 0xFFFFFFFFFFFFFFFEUL
}
let mut value = value_bits.reinterpret_as_int64()
if value != 0L && (value < 0L) != sign {
round_to_i64_invalid(context, sign)
} else if sig_extra != 0UL {
if rounding == Odd {
value = value | 1L
}
{ value, context: round_inexact_context(context, exact), }
} else {
{ value, context, }
}
}
}