Skip to content

Commit

Permalink
Implement Float.round in Inko
Browse files Browse the repository at this point in the history
This also introduces Float.**, which raises a float to the power of some
Int.

This fixes #585.

Changelog: changed
  • Loading branch information
yorickpeterse committed Jul 14, 2023
1 parent cf87e5a commit 524626e
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 35 deletions.
42 changes: 42 additions & 0 deletions compiler/src/llvm/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1061,6 +1061,48 @@ impl<'a, 'b, 'ctx> LowerMethod<'a, 'b, 'ctx> {

self.builder.store(reg_var, res);
}
BuiltinFunction::FloatRound => {
let reg_var = self.variables[&ins.register];
let val_var = self.variables[&ins.arguments[0]];
let val = self.read_float(val_var);
let func = self.module.intrinsic(
"llvm.round",
&[self.builder.context.f64_type().into()],
);

let raw = self
.builder
.call(func, &[val.into()])
.into_float_value();

let res = self.new_float(state_var, raw);

self.builder.store(reg_var, res);
}
BuiltinFunction::FloatPowi => {
let reg_var = self.variables[&ins.register];
let lhs_var = self.variables[&ins.arguments[0]];
let rhs_var = self.variables[&ins.arguments[1]];
let lhs = self.read_float(lhs_var);
let raw_rhs = self.read_int(rhs_var);
let rhs = self.builder.int_to_int(raw_rhs, 32);
let func = self.module.intrinsic(
"llvm.powi",
&[
self.builder.context.f64_type().into(),
self.builder.context.i32_type().into(),
],
);

let raw = self
.builder
.call(func, &[lhs.into(), rhs.into()])
.into_float_value();

let res = self.new_float(state_var, raw);

self.builder.store(reg_var, res);
}
BuiltinFunction::IntRotateLeft => {
let reg_var = self.variables[&ins.register];
let lhs_var = self.variables[&ins.arguments[0]];
Expand Down
27 changes: 0 additions & 27 deletions rt/src/runtime/float.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,33 +31,6 @@ pub unsafe extern "system" fn inko_float_clone(
}
}

#[no_mangle]
pub unsafe extern "system" fn inko_float_round(
state: *const State,
float: f64,
precision: i64,
) -> *const Float {
let result = if precision == 0 {
float.round()
} else if precision <= i64::from(u32::MAX) {
let power = 10.0_f64.powi(precision as i32);
let multiplied = float * power;

// Certain very large numbers (e.g. f64::MAX) would produce Infinity
// when multiplied with the power. In this case we just return the input
// float directly.
if multiplied.is_finite() {
multiplied.round() / power
} else {
float
}
} else {
float
};

Float::alloc((*state).float_class, result)
}

#[no_mangle]
pub unsafe extern "system" fn inko_float_to_string(
state: *const State,
Expand Down
22 changes: 14 additions & 8 deletions std/src/std/float.inko
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,14 @@ import std::cmp::(Compare, Equal, Ordering)
import std::fmt::(Format, Formatter)
import std::hash::(Hash, Hasher)
import std::int::(MAX, MIN, ToInt)
import std::ops::(Add, Divide, Modulo, Multiply, Subtract)
import std::ops::(Add, Divide, Modulo, Multiply, Power, Subtract)
import std::string::ToString

class extern AnyResult {
let @tag: Int
let @value: Any
}

fn extern inko_float_round(
state: Pointer[Int8],
value: Float64,
decimals: Int,
) -> Float

fn extern inko_float_to_string(state: Pointer[Int8], float: Float64) -> String
fn extern inko_string_to_float(
state: Pointer[Int8],
Expand Down Expand Up @@ -191,7 +185,13 @@ class builtin Float {
#
# Float.not_a_number.round.not_a_number? # => true
fn pub round(decimals: Int) -> Float {
inko_float_round(_INKO.state, self as Float64, decimals)
if decimals <= 0 { return _INKO.float_round(self) }
if decimals > 4_294_967_295 { return self }

let pow = 10.0 ** decimals
let mul = self * pow

if mul.infinite? { self } else { _INKO.float_round(mul) / pow }
}

# Returns the fractional part of this float.
Expand Down Expand Up @@ -385,3 +385,9 @@ impl Format for Float {
formatter.write(to_string)
}
}

impl Power[Int, Float] for Float {
fn pub **(other: ref Int) -> Float {
_INKO.float_powi(self, other)
}
}
17 changes: 17 additions & 0 deletions std/test/std/test_float.inko
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import helpers::(fmt, hash)
import std::cmp::Ordering
import std::hash::Hasher
import std::int::(MAX as INT_MAX)
import std::test::Tests

let NAN = 0.0 / 0.0
Expand Down Expand Up @@ -99,9 +100,16 @@ fn pub tests(t: mut Tests) {
}

t.test('Float.round') fn (t) {
t.equal(10.123.round(0), 10.0)
t.equal(10.123.round(1), 10.1)
t.equal(10.123.round(2), 10.12)
t.equal(10.123.round(3), 10.123)
t.equal(10.123.round(6), 10.123)
t.equal(10.123.round(INT_MAX), 10.123)
t.equal(10.123.round(-3), 10.0)
t.equal(Float.negative_infinity.round(3), Float.negative_infinity)
t.equal(Float.infinity.round(3), Float.infinity)
t.true(Float.not_a_number.round(3).not_a_number?)
}

t.test('Float.fractional') fn (t) {
Expand Down Expand Up @@ -287,4 +295,13 @@ fn pub tests(t: mut Tests) {
t.false(-0.0.positive_sign?)
t.false(Float.negative_infinity.positive_sign?)
}

t.test('Float.**') fn (t) {
t.equal(1.2 ** 2, 1.44)
t.equal(1.2 ** 0, 1.0)
t.equal(10.0 ** 2, 100.0)
t.equal(-1.2 ** 2, 1.44)
t.equal(-1.2 ** 0, 1.0)
t.equal(-10.0 ** 2, 100.0)
}
}
8 changes: 8 additions & 0 deletions types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1551,6 +1551,8 @@ pub enum BuiltinFunction {
StringConcat,
State,
Process,
FloatRound,
FloatPowi,
}

impl BuiltinFunction {
Expand Down Expand Up @@ -1599,6 +1601,8 @@ impl BuiltinFunction {
BuiltinFunction::StringConcat,
BuiltinFunction::State,
BuiltinFunction::Process,
BuiltinFunction::FloatRound,
BuiltinFunction::FloatPowi,
]
.into_iter()
.fold(HashMap::new(), |mut map, func| {
Expand Down Expand Up @@ -1652,6 +1656,8 @@ impl BuiltinFunction {
BuiltinFunction::StringConcat => "string_concat",
BuiltinFunction::State => "state",
BuiltinFunction::Process => "process",
BuiltinFunction::FloatRound => "float_round",
BuiltinFunction::FloatPowi => "float_powi",
}
}

Expand Down Expand Up @@ -1704,6 +1710,8 @@ impl BuiltinFunction {
BuiltinFunction::Process => {
TypeRef::pointer(TypeId::Foreign(ForeignType::Int(8)))
}
BuiltinFunction::FloatRound => TypeRef::float(),
BuiltinFunction::FloatPowi => TypeRef::float(),
}
}
}
Expand Down

0 comments on commit 524626e

Please sign in to comment.