Skip to content

Commit

Permalink
Merge pull request sampsyo#398 from Pat-Lafon/scientific_floats
Browse files Browse the repository at this point in the history
Scientific floats
  • Loading branch information
sampsyo authored Feb 11, 2025
2 parents 90014fe + e5d9ff0 commit d41519b
Show file tree
Hide file tree
Showing 16 changed files with 83 additions and 32 deletions.
4 changes: 2 additions & 2 deletions benchmarks/float/exponentiation-by-squaring.out
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
3.083945934529577e+53
1.422023440989732e+137
3.08394593452957709e+53
1.42202344098973190e+137
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions bril-rs/bril2json/src/bril_grammar.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ Ident: String = {
<s : IDENT_TOKEN> => s.to_string(),
"true" => "true".to_owned(),
"false" => "false".to_owned(),
"from" => "from".to_owned(),
}

Args: ParsingArgs = {
Expand Down
4 changes: 2 additions & 2 deletions bril-rs/brillvm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ TESTS := ../../test/interp/core/*.bril \
../../test/interp/float/*.bril \
../../test/interp/ssa/*.bril \
../../test/interp/mem/*.bril \
../../test/interp/mixed/*[^r].bril # A hack to exclude store-char.bril by excluding any file ending in r.bril
../../test/interp/mixed/*[!r].bril # A hack to exclude store-char.bril by excluding any file ending in r.bril

BENCHMARKS := ../../benchmarks/core/*.bril \
../../benchmarks/float/*.bril \
../../benchmarks/mem/*.bril \
../../benchmarks/mixed/*.bril
../../benchmarks/mixed/*[!k].bril # a hack to exclude random_walk.bril because it uses the char extension

build:
cargo build
Expand Down
4 changes: 2 additions & 2 deletions bril-rs/brillvm/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
libc-print = "0.1"
libc = { version = "0.2", default-features = false }

# To properly set up the rt library for linking with LLVM
[profile.dev]
Expand All @@ -15,4 +15,4 @@ lto = true

[profile.release]
panic = "abort"
lto = true
lto = true
41 changes: 28 additions & 13 deletions bril-rs/brillvm/runtime/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,45 +7,60 @@ use std::mem::size_of; */

use core::ffi::{c_char, CStr};

use libc_print::std_name::{print, println};

#[no_mangle]
pub extern "C" fn _bril_print_int(i: i64) {
print!("{}", i);
unsafe {
libc::printf(c"%lld".as_ptr().cast(), i);
}
}

#[no_mangle]
pub extern "C" fn _bril_print_bool(b: bool) {
if b {
print!("true")
} else {
print!("false")
let c_str = if b { c"true" } else { c"false" };
unsafe {
libc::printf(c_str.as_ptr().cast());
}
}

#[no_mangle]
pub extern "C" fn _bril_print_float(f: f64) {
if f.is_infinite() {
if f.is_sign_negative() {
print!("-Infinity");
unsafe {
libc::printf(c"-Infinity".as_ptr().cast());
}
} else {
print!("Infinity");
unsafe {
libc::printf(c"Infinity".as_ptr().cast());
}
}
} else if f.is_nan() {
print!("NaN");
unsafe {
libc::printf(c"NaN".as_ptr().cast());
}
} else if f != 0.0 && (f.abs() >= 1E10 || f.abs() <= 1E-10) {
unsafe {
libc::printf(c"%.17e".as_ptr().cast(), f);
}
} else {
print!("{:.17}", f);
unsafe {
libc::printf(c"%.17lf".as_ptr().cast(), f);
}
}
}

#[no_mangle]
pub extern "C" fn _bril_print_sep() {
print!(" ");
unsafe {
libc::printf(c" ".as_ptr().cast());
}
}

#[no_mangle]
pub extern "C" fn _bril_print_end() {
println!();
unsafe {
libc::printf(c"\n".as_ptr().cast());
}
}

#[no_mangle]
Expand Down
8 changes: 6 additions & 2 deletions brili.ts
Original file line number Diff line number Diff line change
Expand Up @@ -594,8 +594,12 @@ function evalInstr(instr: bril.Instruction, state: State): Action {
let args = instr.args || [];
let values = args.map(function (i) {
let val = get(state.env, i);
if (Object.is(-0, val)) { return "-0.00000000000000000" };
if (typeof val == "number") { return val.toFixed(17) } else {return val.toString()}}
if (typeof val == "number") {
if ( Object.is(-0.0, val)) { return "-" + val.toFixed(17) }
else if (val != 0.0 && Math.abs(Math.log10(Math.abs(val))) >= 10) { return val.toExponential(17) }
else { return val.toFixed(17) }
}
else {return val.toString()}}
);
console.log(...values);
return NEXT;
Expand Down
4 changes: 2 additions & 2 deletions brilift/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Brilift only supports core Bril for now, so we select those tests &
# benchmarks.
TESTS := ../test/interp/core/*.bril ../test/interp/float/*.bril ../test/interp/mem/*.bril ../test/interp/mixed/*[!r].bril # A hack to exclude store-char.bril by excluding any file ending in r.bril
BENCHMARKS := ../benchmarks/core/*.bril ../benchmarks/float/*.bril ../benchmarks/mem/*.bril ../benchmarks/mixed/*.bril
BENCHMARKS := ../benchmarks/core/*.bril ../benchmarks/float/*.bril ../benchmarks/mem/*.bril ../benchmarks/mixed/*[!k].bril # A hack to exclude random_walk.bril because it uses the char extension

CFLAGS := $(if $(TARGET),-target $(TARGET))
BRILFLAGS := $(if $(TARGET),-t $(TARGET))
Expand All @@ -23,7 +23,7 @@ test: rt.o release

.PHONY: benchmark
benchmark: rt.o release
turnt -e brilift-aot -e brilift-jit $(TURNTARGS) $(BENCHMARKS)
turnt --diff -e brilift-aot -e brilift-jit $(TURNTARGS) $(BENCHMARKS)

rt.o: rt.c
cc $(CFLAGS) -c -o $@ $^
Expand Down
2 changes: 2 additions & 0 deletions brilift/rt.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ void _bril_print_float(double f) {
} else {
printf("Infinity");
}
} else if ((f != 0.0) && ((fabs(f) >= 1E10) || (fabs(f) <= 1E-10))) {
printf("%.17e", f);
} else {
printf("%.17lf", f);
}
Expand Down
4 changes: 4 additions & 0 deletions brilift/src/rt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ pub extern "C" fn print_float(f: f64) {
} else {
print!("Infinity");
}
} else if f != 0.0 && f.abs().log10() >= 10.0 {
print!("{}", format!("{f:.17e}").replace('e', "e+").as_str());
} else if f != 0.0 && f.abs().log10() <= -10.0 {
print!("{f:.17e}");
} else {
print!("{f:.17}");
}
Expand Down
10 changes: 10 additions & 0 deletions brilirs/src/interp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,10 @@ impl fmt::Display for Value {
Self::Bool(b) => write!(f, "{b}"),
Self::Float(v) if v.is_infinite() && v.is_sign_positive() => write!(f, "Infinity"),
Self::Float(v) if v.is_infinite() && v.is_sign_negative() => write!(f, "-Infinity"),
Self::Float(v) if v != &0.0 && v.abs().log10() >= 10.0 => {
f.write_str(format!("{v:.17e}").replace('e', "e+").as_str())
}
Self::Float(v) if v != &0.0 && v.abs().log10() <= -10.0 => write!(f, "{v:.17e}"),
Self::Float(v) => write!(f, "{v:.17}"),
Self::Char(c) => write!(f, "{c}"),
Self::Pointer(p) => write!(f, "{p:?}"),
Expand All @@ -213,6 +217,12 @@ fn optimized_val_output<T: std::io::Write>(out: &mut T, val: &Value) -> Result<(
Value::Float(f) if f.is_infinite() && f.is_sign_positive() => out.write_all(b"Infinity"),
Value::Float(f) if f.is_infinite() && f.is_sign_negative() => out.write_all(b"-Infinity"),
Value::Float(f) if f.is_nan() => out.write_all(b"NaN"),
Value::Float(f) if f != &0.0 && f.abs().log10() >= 10.0 => {
out.write_all(format!("{f:.17e}").replace('e', "e+").as_bytes())
}
Value::Float(f) if f != &0.0 && f.abs().log10() <= -10.0 => {
out.write_all(format!("{f:.17e}").as_bytes())
}
Value::Float(f) => out.write_all(format!("{f:.17}").as_bytes()),
Value::Char(c) => {
let buf = &mut [0_u8; 2];
Expand Down
4 changes: 3 additions & 1 deletion docs/lang/float.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ Printing
--------

The [core `print` operation](./core.md#miscellaneous) prints `float` values with 17 decimal digits of precision, including trailing zeros.
(This is like using the `%.17lf` format specifier in C's `printf`.)
For values with magnitude 10¹⁰, it uses exponential notation with suffixes like `e+12`.
(In terms of C's `printf`, this is like using the `%.17lf` format specifier for small values and `%.17e` for large values, i.e., when `f.abs().log10().abs >= 10`.)

Positive and negative zero, while they are equal according to `feq`, look different when printed.
Not-a-number values are printed as `NaN`; infinite values are printed as the strings `Infinity` or `-Infinity`.
22 changes: 14 additions & 8 deletions test/interp/float/float_special.bril
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,18 @@
print v0;
print v1;
print res;
# v2: float = const 1e6;
# v3: float = const 1E-6;
# v4: float = const -1E+6;
# v5: float = const +.11e12;
# print v2;
# print v3;
# print v4;
# print v5;
v2: float = const 1e6;
v3: float = const 1E-6;
v4: float = const -1E+6;
v5: float = const +.11e12;
print v2;
print v3;
print v4;
print v5;
v6: float = const 1e21;
v7: float = const 1e-21;
print v6;
print v7;
v8: float = const 1e5;
print v8;
}
7 changes: 7 additions & 0 deletions test/interp/float/float_special.out
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
0.00000000000000000
-0.00000000000000000
true
1000000.00000000000000000
0.00000100000000000
-1000000.00000000000000000
1.10000000000000000e+11
1.00000000000000000e+21
9.99999999999999908e-22
100000.00000000000000000

0 comments on commit d41519b

Please sign in to comment.