///|
fn barb_derived_finite(value : Double) -> Bool {
!value.is_nan() && !value.is_inf()
}
///|
fn checked_barb_counts(
effective : Double,
half_increment : Double,
full_increment : Double,
flag_increment : Double,
existing_components : Int32,
) -> (Int32, Int32, Int32) raise @core.DataError {
// Keep the original floating-point operations. Conversion follows only once
// every derived count and the resulting array length is representable.
let flags = (effective / flag_increment).floor()
let after_flags = effective - flags * flag_increment
let fulls = (after_flags / full_increment).floor()
let remainder = after_flags - fulls * full_increment
let half = if remainder + 1.0e-12 >= half_increment { 1 } else { 0 }
let components = 1.0 +
flags.max(0.0) +
fulls.max(0.0) +
Double::from_int(half)
if !barb_derived_finite(effective) ||
!barb_derived_finite(flags) ||
!barb_derived_finite(after_flags) ||
!barb_derived_finite(fulls) ||
!barb_derived_finite(remainder) ||
!barb_derived_finite(components) ||
flags < -2147483648.0 ||
flags > 2147483647.0 ||
fulls < -2147483648.0 ||
fulls > 2147483647.0 ||
components > 2147483647.0 - Double::from_int(existing_components) {
raise @core.DataError::InvalidQuiver(
message="barb derived component counts must be finite and representable",
)
}
(flags.to_int(), fulls.to_int(), half)
}