Allow big numbers as input, #130

This commit is contained in:
PaddiM8 2024-04-03 01:34:35 +02:00
parent 8ffc0e1e9d
commit f846a5b59e
5 changed files with 29 additions and 38 deletions

View File

@ -1,4 +1,4 @@
use crate::lexer::TokenKind; use crate::{kalk_value::KalkFloat, lexer::TokenKind};
/// A tree structure of a statement. /// A tree structure of a statement.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -19,10 +19,7 @@ pub enum Expr {
Var(Identifier), Var(Identifier),
Group(Box<Expr>), Group(Box<Expr>),
FnCall(Identifier, Vec<Expr>), FnCall(Identifier, Vec<Expr>),
#[cfg(feature="rug")] Literal(KalkFloat),
Literal(rug::Float),
#[cfg(not(feature="rug"))]
Literal(f64),
Boolean(bool), Boolean(bool),
Piecewise(Vec<ConditionalPiece>), Piecewise(Vec<ConditionalPiece>),
Vector(Vec<Expr>), Vector(Vec<Expr>),

View File

@ -2,6 +2,7 @@ use crate::ast::{Expr, Stmt};
use crate::ast::{Identifier, RangedVar}; use crate::ast::{Identifier, RangedVar};
use crate::calculation_result::CalculationResult; use crate::calculation_result::CalculationResult;
use crate::errors::KalkError; use crate::errors::KalkError;
use crate::kalk_value::KalkFloat;
use crate::kalk_value::KalkValue; use crate::kalk_value::KalkValue;
use crate::lexer::TokenKind; use crate::lexer::TokenKind;
use crate::parser::DECL_UNIT; use crate::parser::DECL_UNIT;
@ -323,28 +324,20 @@ fn eval_var_expr(
} }
#[allow(unused_variables)] #[allow(unused_variables)]
#[cfg(feature = "rug")]
fn eval_literal_expr( fn eval_literal_expr(
context: &mut Context, context: &mut Context,
value: rug::Float, value: KalkFloat,
unit: Option<&String>, unit: Option<&String>,
) -> Result<KalkValue, KalkError> { ) -> Result<KalkValue, KalkError> {
#[allow(unused_mut)]
let mut float = float!(value); let mut float = float!(value);
#[cfg(feature = "rug")]
float.set_prec(context.precision); float.set_prec(context.precision);
Ok(KalkValue::Number(float, float!(0), unit.cloned())) Ok(KalkValue::Number(float, float!(0), unit.cloned()))
} }
#[allow(unused_variables)]
#[cfg(not(feature = "rug"))]
fn eval_literal_expr(
context: &mut Context,
value: f64,
unit: Option<&String>,
) -> Result<KalkValue, KalkError> {
Ok(KalkValue::Number(float!(value), float!(0), unit.cloned()))
}
fn eval_group_expr( fn eval_group_expr(
context: &mut Context, context: &mut Context,
expr: &Expr, expr: &Expr,

View File

@ -18,6 +18,12 @@ use self::rounding::EstimationResult;
const ACCEPTABLE_COMPARISON_MARGIN: f64 = 0.00000001; const ACCEPTABLE_COMPARISON_MARGIN: f64 = 0.00000001;
#[cfg(feature = "rug")]
pub(crate) type KalkFloat = rug::Float;
#[cfg(not(feature = "rug"))]
pub(crate) type KalkFloat = f64;
#[macro_export] #[macro_export]
#[cfg(not(feature = "rug"))] #[cfg(not(feature = "rug"))]
macro_rules! float { macro_rules! float {

View File

@ -4,6 +4,7 @@ use crate::analysis;
use crate::ast::Identifier; use crate::ast::Identifier;
use crate::calculation_result::CalculationResult; use crate::calculation_result::CalculationResult;
use crate::errors::KalkError; use crate::errors::KalkError;
use crate::kalk_value::KalkFloat;
use crate::{ use crate::{
ast::{Expr, Stmt}, ast::{Expr, Stmt},
interpreter, interpreter,
@ -770,8 +771,8 @@ fn skip_newlines(context: &mut Context) {
} }
} }
fn string_to_num(value: &str) -> Result<KalkFloat, KalkError> {
#[cfg(feature = "rug")] #[cfg(feature = "rug")]
fn string_to_num(value: &str) -> Result<rug::Float, KalkError> {
use rug::ops::Pow; use rug::ops::Pow;
if value.contains('E') { if value.contains('E') {
@ -779,24 +780,10 @@ fn string_to_num(value: &str) -> Result<rug::Float, KalkError> {
let left = crate::float!(string_to_num(parts[0])?); let left = crate::float!(string_to_num(parts[0])?);
let right = crate::float!(string_to_num(parts[1])?); let right = crate::float!(string_to_num(parts[1])?);
#[cfg(feature = "rug")]
return Ok(left * 10.pow(right)); return Ok(left * 10.pow(right));
}
let base = get_base(value)?;
if let Some(result) = crate::radix::parse_float_radix(&value.replace(' ', ""), base) {
Ok(crate::float!(result))
} else {
Err(KalkError::InvalidNumberLiteral(value.into()))
}
}
#[cfg(not(feature = "rug"))] #[cfg(not(feature = "rug"))]
fn string_to_num(value: &str) -> Result<f64, KalkError> {
if value.contains('E') {
let parts = value.split('E').collect::<Vec<_>>();
let left = crate::float!(string_to_num(parts[0])?);
let right = crate::float!(string_to_num(parts[1])?);
return Ok(left * 10_f64.powf(right)); return Ok(left * 10_f64.powf(right));
} }

View File

@ -1,13 +1,21 @@
pub fn parse_float_radix(value: &str, radix: u8) -> Option<f64> { use crate::{float, kalk_value::KalkFloat};
pub fn parse_float_radix(value: &str, radix: u8) -> Option<KalkFloat> {
if radix == 10 { if radix == 10 {
return if let Ok(result) = value.parse::<f64>() { #[cfg(feature = "rug")]
let parsed = rug::Float::parse(value).map(|valid| crate::float!(valid));
#[cfg(not(feature = "rug"))]
let parsed = value.parse::<f64>();
return if let Ok(result) = parsed {
Some(result) Some(result)
} else { } else {
None None
}; };
} }
let mut sum = 0f64; let mut sum = float!(0f64);
let length = value.find('_').unwrap_or(value.len()); let length = value.find('_').unwrap_or(value.len());
let mut i = (value.find('.').unwrap_or(length) as i32) - 1; let mut i = (value.find('.').unwrap_or(length) as i32) - 1;
for c in value.chars() { for c in value.chars() {