Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gcd shows wrong result when input number is too large #119

Open
abiriadev opened this issue Jun 12, 2023 · 8 comments
Open

gcd shows wrong result when input number is too large #119

abiriadev opened this issue Jun 12, 2023 · 8 comments

Comments

@abiriadev
Copy link

Actual Behavior

>> gcd(500000000000000000, 500000000000000002)
500 000 000 000 000 000 ≈ 5×10^17

Expected result

2

Suggestion

I think it would be more helpful to warn a user if the input value is larger than some amount.
And I am willing to contribute or send PR if needed.

Regards.

@PaddiM8
Copy link
Owner

PaddiM8 commented Jun 12, 2023

Hm yeah. Not even sure why this happens. It would make sense to warn the user, but I'm not sure there's a way to do that currently, while still giving a result. If we figure out when exactly this happens, it might make sense to simply return an error if the input is too large (for now at least). It seems to be when both are a certain size, but I haven't found a more specific pattern yet.

@abiriadev
Copy link
Author

I'd be happy to help or contribute in any way if I can (and have enough time).

Could you please point me to where the gcd implementation is located? I think it might be a good starting point to identify the issue.

@PaddiM8
Copy link
Owner

PaddiM8 commented Jun 12, 2023

Great! That might speed things up, since I also have limited time right now. The function is implemented here:

pub fn gcd(x: KalkValue, y: KalkValue) -> Result<KalkValue, KalkError> {

KalkValue represents a value in kalk, usually a number. Normally, this is a heap allocated big float, but for the web version it's just an f64, since the big float library doesn't support WebAssembly. To be able to write generic code despite this, there is a float! macro that turns a number into the relevant type.

@dvishal485
Copy link
Contributor

How can float! be useful here? I don't think it will resolve issue regarding number not being able to stored in heap with precision. Am I missing something here?

#[macro_export]
#[cfg(not(feature = "rug"))]
macro_rules! float {
($x:expr) => {{
$x.clone() as f64
}};
}
#[macro_export]
#[cfg(feature = "rug")]
macro_rules! float {
($x:expr) => {{
use rug::Float;
Float::with_val(63, $x)
}};
}

I would love to contribute if I understand the issue completely.

@PaddiM8
Copy link
Owner

PaddiM8 commented Nov 29, 2023

The purpose of float! is to create a rug::Float or f64, depending on if the rug feature is enabled. Unfortunately it doesn't get the configured precision.

@dvishal485
Copy link
Contributor

I believe it has something to do with the fact that float! macro always get an f64 value because parsing of Literals was done with f64.

Literal(f64),

kalker/kalk/src/ast.rs

Lines 13 to 30 in e9c9e81

/// A tree structure of an expression.
#[derive(Debug, Clone, PartialEq)]
pub enum Expr {
Binary(Box<Expr>, TokenKind, Box<Expr>),
Unary(TokenKind, Box<Expr>),
Unit(String, Box<Expr>),
Var(Identifier),
Group(Box<Expr>),
FnCall(Identifier, Vec<Expr>),
Literal(f64),
Boolean(bool),
Piecewise(Vec<ConditionalPiece>),
Vector(Vec<Expr>),
Matrix(Vec<Vec<Expr>>),
Indexer(Box<Expr>, Vec<Expr>),
Comprehension(Box<Expr>, Vec<Expr>, Vec<RangedVar>),
Equation(Box<Expr>, Box<Expr>, Identifier),
}

So no matter what you do with float!(), you will always be passing it f64 with less precision and hence value may be different than what it was asked to parse originally.

I don't know if I am right on this, but it is a best guess about the source of "error" I could make as a newbie.

@PaddiM8
Copy link
Owner

PaddiM8 commented Nov 30, 2023

Hm yeah that sounds about right yeah. It should probably be a rug float when the rug feature is enabled.

@dvishal485
Copy link
Contributor

I have changed a lot of things in codebase to fix this. Everything compiles and test out just fine with rug feature enabled as well as disabled. Making a PR for the same.

This would parse strings with correct precision instead of loading them into f64 and then making them Float. Tested with the input 500000000000000002 which works fine now. You may want to rearrange the codebase to accommodate some functions I added, and rename/remove some existing functions.

Unfortunately for without rug crate, it would use f64.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants