Began adding rationals

This commit is contained in:
PaddiM8 2020-12-13 17:15:57 +01:00
parent 1cbc5004d5
commit e9ae651572
3 changed files with 72 additions and 11 deletions

View File

@ -184,9 +184,11 @@ pub fn convert_unit(
.symbol_table .symbol_table
.insert(Stmt::VarDecl(DECL_UNIT.into(), Box::new(expr.clone()))); .insert(Stmt::VarDecl(DECL_UNIT.into(), Box::new(expr.clone())));
Ok(KalkNum::new( let num = eval_expr(context, &unit_def, "")?;
eval_expr(context, &unit_def, "")?.value, Ok(KalkNum::new_with_rational(
num.clone().value,
to_unit.into(), to_unit.into(),
num.get_internal_rational(),
)) ))
} else { } else {
Err(CalcError::InvalidUnit) Err(CalcError::InvalidUnit)
@ -243,7 +245,7 @@ fn eval_fn_call_expr(
}; };
if let Some((result, func_unit)) = prelude_func { if let Some((result, func_unit)) = prelude_func {
return Ok(KalkNum::new( return Ok(KalkNum::new_without_rational(
result, result,
if unit.len() > 0 { unit } else { &func_unit }, if unit.len() > 0 { unit } else { &func_unit },
)); ));

View File

@ -1,11 +1,13 @@
use crate::ast::Expr; use crate::ast::Expr;
use rug::ops::Pow; use rug::ops::Pow;
use rug::Float; use rug::Float;
use rug::Rational;
#[derive(PartialEq, Debug, Clone)] #[derive(PartialEq, Debug, Clone)]
pub struct KalkNum { pub struct KalkNum {
pub(crate) value: Float, pub(crate) value: Float,
pub(crate) unit: String, pub(crate) unit: String,
rational: Option<Rational>,
} }
pub struct ScientificNotation { pub struct ScientificNotation {
@ -34,8 +36,25 @@ impl ScientificNotation {
impl KalkNum { impl KalkNum {
pub fn new(value: Float, unit: &str) -> Self { pub fn new(value: Float, unit: &str) -> Self {
Self { Self {
value, value: value.clone(),
unit: unit.to_string(), unit: unit.to_string(),
rational: value.to_rational(),
}
}
pub(crate) fn new_with_rational(value: Float, unit: &str, rational: Option<Rational>) -> Self {
Self {
value: value.clone(),
unit: unit.to_string(),
rational: rational,
}
}
pub fn new_without_rational(value: Float, unit: &str) -> Self {
Self {
value: value.clone(),
unit: unit.to_string(),
rational: None,
} }
} }
@ -68,6 +87,16 @@ impl KalkNum {
&self.unit &self.unit
} }
pub fn get_rational(self) -> Option<(i64, i64)> {
let (numer, denom) = self.rational?.into_numer_denom();
Some((numer.to_i64()?, denom.to_i64()?))
}
pub fn get_internal_rational(self) -> Option<Rational> {
self.rational
}
pub fn has_unit(&self) -> bool { pub fn has_unit(&self) -> bool {
self.unit.len() > 0 self.unit.len() > 0
} }
@ -109,32 +138,52 @@ impl KalkNum {
pub fn add(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum { pub fn add(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum {
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs); let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
KalkNum::new(self.value + right.value, &right.unit) let mut num = KalkNum::new_without_rational(self.value + right.value, &right.unit);
if let (Some(left_rational), Some(right_rational)) = (self.rational, right.rational) {
num.rational = Some(left_rational + right_rational);
};
num
} }
pub fn sub(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum { pub fn sub(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum {
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs); let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
KalkNum::new(self.value - right.value, &right.unit) let mut num = KalkNum::new_without_rational(self.value - right.value, &right.unit);
if let (Some(left_rational), Some(right_rational)) = (self.rational, right.rational) {
num.rational = Some(left_rational - right_rational);
};
num
} }
pub fn mul(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum { pub fn mul(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum {
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs); let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
KalkNum::new(self.value * right.value, &right.unit) let mut num = KalkNum::new_without_rational(self.value * right.value, &right.unit);
if let (Some(left_rational), Some(right_rational)) = (self.rational, right.rational) {
num.rational = Some(left_rational * right_rational);
};
num
} }
pub fn div(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum { pub fn div(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum {
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs); let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
KalkNum::new(self.value / right.value, &right.unit) let mut num = KalkNum::new_without_rational(self.value / right.value, &right.unit);
if let (Some(left_rational), Some(right_rational)) = (self.rational, right.rational) {
num.rational = Some(left_rational / right_rational);
};
num
} }
pub fn rem(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum { pub fn rem(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum {
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs); let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
KalkNum::new(self.value % right.value, &right.unit) KalkNum::new_without_rational(self.value % right.value, &right.unit)
} }
pub fn pow(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum { pub fn pow(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum {
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs); let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
KalkNum::new(self.value.pow(right.value), &right.unit) KalkNum::new_without_rational(self.value.pow(right.value), &right.unit)
} }
} }
@ -146,7 +195,11 @@ fn calculate_unit(
if left.has_unit() && right.has_unit() { if left.has_unit() && right.has_unit() {
right.convert_to_unit(context, &left.unit) right.convert_to_unit(context, &left.unit)
} else { } else {
Some(KalkNum::new(right.value, &left.unit)) Some(KalkNum::new_with_rational(
right.value,
&left.unit,
right.rational,
))
} }
} }

View File

@ -12,6 +12,12 @@ pub fn eval(parser: &mut parser::Context, input: &str) {
}; };
println!("{} {}", result_str, result.get_unit()); println!("{} {}", result_str, result.get_unit());
if result_str.contains(".") {
if let Some((numer, denom)) = result.get_rational() {
println!("{}/{}", numer, denom);
}
}
} }
Ok(None) => print!(""), Ok(None) => print!(""),
Err(err) => print_calc_err(err), Err(err) => print_calc_err(err),