mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 15:21:12 +00:00
Implement RocDec to [u8] algorithm.
This commit is contained in:
parent
dc92de7781
commit
a021c09752
2 changed files with 51 additions and 26 deletions
|
@ -326,9 +326,7 @@ fn jit_to_ast_help<'a, A: ReplApp<'a>>(
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
Layout::Builtin(Builtin::Decimal) => {
|
Layout::Builtin(Builtin::Decimal) => Ok(helper!(RocDec)),
|
||||||
Ok(helper!(RocDec))
|
|
||||||
}
|
|
||||||
Layout::Builtin(Builtin::Str) => {
|
Layout::Builtin(Builtin::Str) => {
|
||||||
let size = layout.stack_size(env.target_info) as usize;
|
let size = layout.stack_size(env.target_info) as usize;
|
||||||
Ok(
|
Ok(
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
#![crate_type = "lib"]
|
#![crate_type = "lib"]
|
||||||
#![no_std]
|
// #![no_std]
|
||||||
use core::ffi::c_void;
|
use core::ffi::c_void;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::mem::{ManuallyDrop, MaybeUninit};
|
use core::mem::{ManuallyDrop, MaybeUninit};
|
||||||
use core::ops::Drop;
|
use core::ops::Drop;
|
||||||
use core::str;
|
use core::str;
|
||||||
// use roc_error_macros::internal_error;
|
use std::io::Write;
|
||||||
// uncomment when we figure out why it fails below.
|
|
||||||
|
|
||||||
mod rc;
|
mod rc;
|
||||||
mod roc_list;
|
mod roc_list;
|
||||||
|
@ -217,9 +216,10 @@ impl RocDec {
|
||||||
pub const MIN: Self = Self(i128::MIN);
|
pub const MIN: Self = Self(i128::MIN);
|
||||||
pub const MAX: Self = Self(i128::MAX);
|
pub const MAX: Self = Self(i128::MAX);
|
||||||
|
|
||||||
pub const DECIMAL_PLACES: u32 = 18;
|
const DECIMAL_PLACES: usize = 18;
|
||||||
|
const ONE_POINT_ZERO: i128 = 10i128.pow(Self::DECIMAL_PLACES as u32);
|
||||||
pub const ONE_POINT_ZERO: i128 = 10i128.pow(Self::DECIMAL_PLACES);
|
const MAX_DIGITS: usize = 39;
|
||||||
|
const MAX_STR_LENGTH: usize = Self::MAX_DIGITS + 2; // + 2 here to account for the sign & decimal dot
|
||||||
|
|
||||||
#[allow(clippy::should_implement_trait)]
|
#[allow(clippy::should_implement_trait)]
|
||||||
pub fn from_str(value: &str) -> Option<Self> {
|
pub fn from_str(value: &str) -> Option<Self> {
|
||||||
|
@ -234,7 +234,7 @@ impl RocDec {
|
||||||
};
|
};
|
||||||
|
|
||||||
let opt_after_point = match parts.next() {
|
let opt_after_point = match parts.next() {
|
||||||
Some(answer) if answer.len() <= Self::DECIMAL_PLACES as usize => Some(answer),
|
Some(answer) if answer.len() <= Self::DECIMAL_PLACES => Some(answer),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -250,7 +250,7 @@ impl RocDec {
|
||||||
Ok(answer) => {
|
Ok(answer) => {
|
||||||
// Translate e.g. the 1 from 0.1 into 10000000000000000000
|
// Translate e.g. the 1 from 0.1 into 10000000000000000000
|
||||||
// by "restoring" the elided trailing zeroes to the number!
|
// by "restoring" the elided trailing zeroes to the number!
|
||||||
let trailing_zeroes = Self::DECIMAL_PLACES as usize - after_point.len();
|
let trailing_zeroes = Self::DECIMAL_PLACES - after_point.len();
|
||||||
let lo = answer * 10i128.pow(trailing_zeroes as u32);
|
let lo = answer * 10i128.pow(trailing_zeroes as u32);
|
||||||
|
|
||||||
if !before_point.starts_with('-') {
|
if !before_point.starts_with('-') {
|
||||||
|
@ -269,7 +269,7 @@ impl RocDec {
|
||||||
|
|
||||||
// Calculate the high digits - the ones before the decimal point.
|
// Calculate the high digits - the ones before the decimal point.
|
||||||
match before_point.parse::<i128>() {
|
match before_point.parse::<i128>() {
|
||||||
Ok(answer) => match answer.checked_mul(10i128.pow(Self::DECIMAL_PLACES)) {
|
Ok(answer) => match answer.checked_mul(Self::ONE_POINT_ZERO) {
|
||||||
Some(hi) => hi.checked_add(lo).map(Self),
|
Some(hi) => hi.checked_add(lo).map(Self),
|
||||||
None => None,
|
None => None,
|
||||||
},
|
},
|
||||||
|
@ -281,29 +281,56 @@ impl RocDec {
|
||||||
Self::from_str(val).unwrap().0
|
Self::from_str(val).unwrap().0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_str_helper(&self, bytes: &mut [u8; 1]) {
|
fn to_str_helper(&self, bytes: &mut [u8; Self::MAX_STR_LENGTH]) {
|
||||||
bytes[0] = 0;
|
if self.0 == 0 {
|
||||||
// TODO
|
write!(&mut bytes[..], "{}", "0.0").unwrap();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let is_negative = (self.0 < 0) as usize;
|
||||||
|
|
||||||
|
write!(&mut bytes[..], "{:019}", self.0).unwrap();
|
||||||
|
// By using the :019 format, we're guaranteeing that numbers less than 1, say 0.01234
|
||||||
|
// get their leading zeros placed in bytes for us. i.e. bytes = b"0012340000000000000"
|
||||||
|
|
||||||
|
// If self represents 1234.5678, then bytes is b"1234567800000000000000".
|
||||||
|
let mut i = Self::DECIMAL_PLACES;
|
||||||
|
// Find the last place where we have actual data.
|
||||||
|
while bytes[i] == 0 {
|
||||||
|
i = i - 1;
|
||||||
|
}
|
||||||
|
// At this point i is 21 because bytes[21] is the final '0' in b"1234567800000000000000".
|
||||||
|
|
||||||
|
let decimal_location = i - Self::DECIMAL_PLACES + 1 + is_negative;
|
||||||
|
// decimal_location = 4
|
||||||
|
|
||||||
|
while bytes[i] == ('0' as u8) {
|
||||||
|
bytes[i] = 0;
|
||||||
|
i = i - 1;
|
||||||
|
}
|
||||||
|
// Now i = 7, because bytes[7] = '8', and bytes = b"12345678"
|
||||||
|
|
||||||
|
while i >= decimal_location {
|
||||||
|
bytes[i + 1] = bytes[i];
|
||||||
|
}
|
||||||
|
// Now i = 4, and bytes = b"123455678"
|
||||||
|
|
||||||
|
bytes[i] = '.' as u8;
|
||||||
|
// Finally bytes = b"1234.5678"
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_str(&self) -> RocStr {
|
pub fn to_str(&self) -> RocStr {
|
||||||
let mut bytes: [u8; 1] = [0];
|
let mut bytes = [0 as u8; Self::MAX_STR_LENGTH];
|
||||||
self.to_str_helper(&mut bytes);
|
self.to_str_helper(&mut bytes);
|
||||||
unsafe {RocStr::from_slice(&bytes) }
|
unsafe { RocStr::from_slice(&bytes) }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for RocDec {
|
impl fmt::Display for RocDec {
|
||||||
fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let mut bytes: [u8; 1] = [0];
|
let mut bytes = [0 as u8; Self::MAX_STR_LENGTH];
|
||||||
self.to_str_helper(&mut bytes);
|
self.to_str_helper(&mut bytes);
|
||||||
match str::from_utf8(&bytes) {
|
let result = unsafe { str::from_utf8_unchecked(&bytes) };
|
||||||
Ok(slice) => write!(fmtr, "{}", slice),
|
write!(fmtr, "{}", result)
|
||||||
Err(payload) => panic!("Error in converting RocDec({}) to a string: {}", self.0, payload),
|
|
||||||
// Err(payload) => internal_error!("Error in converting RocDec({}) to a string: {}", self.0, payload),
|
|
||||||
// This raises a compile error: can't find eprintln
|
|
||||||
// Is this because we don't use std?
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue