Added support for scientific notation

pull/2/head
Mark 2023-04-01 18:29:01 -07:00
parent 52a508cd98
commit 85a669e126
Signed by: Mark
GPG Key ID: AD62BB059C2AAEE4
3 changed files with 103 additions and 14 deletions

View File

@ -176,6 +176,13 @@ fn main() -> Result<(), std::io::Error> {
// Tests to add: // Tests to add:
// 3!+1 // 3!+1
// 3!3 // 3!3
// 1e2
// 1e-2
// 1e0
// 1e1.2
// 1e(2)
// e2e
// 2 2e2
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View File

@ -31,6 +31,24 @@ fn push_token(g: &mut VecDeque<PreToken>, t: Option<PreToken>, stop_i: usize) {
}; };
// `2e` isn't exponential notation, it's 2*e.
// If a number ends in `e`, disconnect the `e` and make it a word.
if let PreToken::PreNumber(l, s) = &t {
let last = &s[s.len()-1..];
if last == "e" {
g.push_back(PreToken::PreNumber(
LineLocation { pos: l.pos, len: l.len-1 },
String::from(&s[0..s.len()-1])
));
g.push_back(PreToken::PreWord(
LineLocation { pos: l.pos + l.len - 1, len: 1 },
String::from("e")
));
return;
}
}
if let PreToken::PreWord(l, s) = &t { if let PreToken::PreWord(l, s) = &t {
let o = Operator::from_string(s); let o = Operator::from_string(s);
if o.is_some() { if o.is_some() {
@ -68,14 +86,50 @@ pub(in crate::parser) fn tokenize(input: &String) -> VecDeque<PreToken> {
}; };
}, },
// The minus sign can be both a Negative and an Operator. // 'e' needs special treatment.
// Needs special treatment, always starts a new token. // Can be both a word or a number.
'e' => {
match &mut t {
Some(PreToken::PreWord(_, val)) => { val.push(c); },
Some(PreToken::PreNumber(_, val)) => { val.push(c); },
_ => {
push_token(&mut g, t, i);
t = Some(PreToken::PreWord(LineLocation{pos: i, len: 0}, String::from(c)));
}
};
}
// The minus sign also needs special treatment.
// It can be the `neg` operator, the `minus` operator,
// or it can specify a negative exponent.
'-' => { '-' => {
push_token(&mut g, t, i); match &mut t {
t = Some(PreToken::PreOperator( Some(PreToken::PreNumber(_, val)) => {
LineLocation{pos: i, len: 1}, if &val[val.len()-1..] == "e" {
String::from("-") // If the current number ends in an `e`,
)); // this negative specifies a negative exponent
// like 2e-2 = 0.02.
val.push(c);
} else {
// Otherwise, end the number.
// We probably have a subtraction.
push_token(&mut g, t, i);
t = Some(PreToken::PreOperator(
LineLocation{pos: i, len: 1},
String::from("-")
));
}
},
_ => {
push_token(&mut g, t, i);
t = Some(PreToken::PreOperator(
LineLocation{pos: i, len: 1},
String::from("-")
));
}
};
}, },
// Operator // Operator

View File

@ -137,20 +137,48 @@ impl Quantity {
pub fn new_rational_from_float_string(s: &str) -> Option<Quantity> { pub fn new_rational_from_float_string(s: &str) -> Option<Quantity> {
let mut q = s.split("."); // Scientific notation
let a = q.next().unwrap(); let mut sci = s.split("e");
let b = q.next(); let num = sci.next().unwrap();
let exp = sci.next();
let exp = if exp.is_some() {
let r = exp.unwrap().parse::<isize>();
match r {
Ok(x) => x,
Err(_) => return None
}
} else {0isize};
// Split integer and decimal parts
let mut dec = num.split(".");
let a = dec.next().unwrap();
let b = dec.next();
let b = if b.is_some() {b.unwrap()} else {""}; let b = if b.is_some() {b.unwrap()} else {""};
// Error conditions // Error conditions
if { if {
q.next().is_some() || // We should have at most one `.` dec.next().is_some() || // We should have at most one `.`
sci.next().is_some() || // We should have at most one `e`
a.len() == 0 // We need something in the numerator a.len() == 0 // We need something in the numerator
} { return None; } } { return None; }
return Some(Quantity::new_rational_from_string( let s: String;
&format!("{a}{b}/1{}", "0".repeat(b.len())) if exp < 0 {
)); let exp: usize = (-exp).try_into().unwrap();
s = format!("{a}{b}/1{}", "0".repeat(b.len() + exp));
} else if exp > 0 {
let exp: usize = exp.try_into().unwrap();
s = format!(
"{a}{b}{}/1{}",
"0".repeat(exp),
"0".repeat(b.len())
);
} else { // exp == 0
s = format!("{a}{b}/1{}", "0".repeat(b.len()));
};
return Quantity::new_rational_from_string(&s);
} }
pub fn to_float(&self) -> Float { pub fn to_float(&self) -> Float {