Giter Site home page Giter Site logo

fraction's People

Contributors

christopherrabotin avatar dnsl48 avatar dralta avatar eutampieri avatar feefladder avatar hbina avatar javamonn avatar joseluis avatar jqnatividad avatar morri2 avatar optevo avatar pthariensflame avatar saona-raimundo avatar scott-wilson avatar squ1dd13 avatar stijnfrishert avatar tan-wei avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

fraction's Issues

Add From for f64 and f32

It would be nice to have api for directly converting to floats, since conversion cannot fail (as far as I know)

Overflow with small number of multiplication

In the following example, the computation of g_rad will cause an overflow in either of the functions. This overflow error does not occur when compiled in release mode because rust does not do bound checking in release mode.


extern crate fraction;
use crate::fraction::GenericDecimal;
pub type Decimal = GenericDecimal<u128, u16>;
use std::f64::consts::TAU;

fn as_single_call() -> Decimal {
    let tt = -0.0000000000002962836210611707;

    let circ_ratio = Decimal::from(TAU) / Decimal::from(360.0);

    let multiplication = Decimal::from(35_999.050 * tt);

    let sum = Decimal::from(357.528) + multiplication;

    dbg!(sum);
    dbg!(circ_ratio);

    let g_rad = circ_ratio * sum; // <==== This is the line which fails (line 79 in my editor)
    g_rad
}

fn as_several_calls() -> Decimal {
    let tt = -0.0000000000002962836210611707;

    let g_rad = (Decimal::from(TAU) / Decimal::from(360.0))
        * (Decimal::from(357.528) + Decimal::from(35_999.050 * tt));
    g_rad
}

fn main() {
    let sgl = as_single_call();
    let svl = as_several_calls();
    println!("{}\n{}", sgl, svl);
}

Output in release mode:

RUST_BACKTRACE=1 cargo run --release
   Compiling paraod v0.1.0 (/home/chris/Workspace/rust/paraod)
    Finished release [optimized] target(s) in 0.74s
     Running `target/release/paraod`
[src/main.rs:76] sum = GenericDecimal(357.527999989334071111237863 | prec=24; Rational(Plus, Ratio { numer: 357527999989334071111237863, denom: 1000000000000000000000000 }); 357.527999989334071111237863)
[src/main.rs:77] circ_ratio = GenericDecimal(0.017453292519943 | prec=15; Rational(Plus, Ratio { numer: 3141592653589793, denom: 180000000000000000 }); 0.01745329251994329444444444444444)
0.832634730828580153746246
0.832634730828580153746246

Output in debug mode:

 RUST_BACKTRACE=1 cargo run          
   Compiling paraod v0.1.0 (/home/chris/Workspace/rust/paraod)
    Finished dev [unoptimized + debuginfo] target(s) in 0.40s
     Running `target/debug/paraod`
[src/main.rs:76] sum = GenericDecimal(357.527999989334071111237863 | prec=24; Rational(Plus, Ratio { numer: 357527999989334071111237863, denom: 1000000000000000000000000 }); 357.527999989334071111237863)
[src/main.rs:77] circ_ratio = GenericDecimal(0.017453292519943 | prec=15; Rational(Plus, Ratio { numer: 3141592653589793, denom: 180000000000000000 }); 0.01745329251994329444444444444444)
thread 'main' panicked at 'attempt to multiply with overflow', /home/chris/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/arith.rs:323:1
stack backtrace:
   0: rust_begin_unwind
             at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/std/src/panicking.rs:475
   1: core::panicking::panic_fmt
             at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/core/src/panicking.rs:85
   2: core::panicking::panic
             at /rustc/18bf6b4f01a6feaf7259ba7cdae58031af1b7b39/library/core/src/panicking.rs:50
   3: <u128 as core::ops::arith::Mul>::mul
             at /home/chris/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/arith.rs:316
   4: <num_rational::Ratio<T> as core::ops::arith::Mul>::mul
             at /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/num-rational-0.2.4/src/lib.rs:766
   5: <fraction::fraction::GenericFraction<T> as core::ops::arith::Mul>::mul
             at /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/fraction-0.6.3/src/fraction/mod.rs:1153
   6: <fraction::decimal::GenericDecimal<T,P> as core::ops::arith::Mul>::mul
             at /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/fraction-0.6.3/src/decimal/mod.rs:130
   7: paraod::as_single_call
             at ./src/main.rs:79
   8: paraod::main
             at ./src/main.rs:92
   9: core::ops::function::FnOnce::call_once
             at /home/chris/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:227
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

Using `calc_precision` on `1 / 3` does not terminate

fraction version: 0.6.3

Problem

For a project that uses fraction I want to implement scientific notation printing of numbers. Sometimes get_precision() does not reflect the actual precision currently used (for example 1 / 100 vs from_decimal_str("0.001")), but using calc_precision() updates this. However this function never terminates for 1 / 3.

use fraction::BigDecimal;

fn main() {
    let x = BigDecimal::from(1) / BigDecimal::from(3);
    dbg!(x.calc_precision());
}

eligible for funding via thanks.dev

Hi Serge, thanks for all your contributions to open source.
I just wanted to let you know that you're eligible to claim funding for your package from our sponsor Sentry. Let me know if this is something you'd like to claim via thanks.dev.

Do not simplify fractions

Hi, I am encountering a problem with the Fraction crate where the simplification of the fraction causes a loss in data.

Here is the explanation:
I need to keep track of a percentage over time. The percentage is for example Bad apples out of the total apples. So i can keep track of the percentage of bad apples.
Let's say we iterate over the apple for each bad apple i increment the denominator AND the nominator. if we start with a bad apple it is 1/1 so 100%, next round a good apple, so i increment only the denominator: 1/2 so 50%.
Now we start with a good apple. We have 0/1 so 0%. And if we have a second good apple after that. I still increment only the denominator. This makes 0/2. but it is simplified with 0/1 and i just lost track of how much apples are bad.

I hope you understand what i mean and that it is relevant.

Thank you

What does it mean that a value cannot be represented by `Ratio<T>`?

I use this crate to convert an f64 into an fps value (video framerate) consisting of u32 numerator and denominator. The documentation for Ratio::<u32>::from_f64() reads:

Converts a f64 to return an optional value of this type. If the value cannot be represented by this type, then None is returned.

I did a few tests and transformed your explanation into the following doc comment for my Fps::from_f64() function:

Panics if, irrationally for a frame rate, the value is so large that a u32 numerator can't describe it.

Is that accurate and does it cover everything?

My observations (using pi, shifting the decimal point):

  • A smaller and smaller value kills precision after a certain point. E.g., 0.0000000000314159 gives me numerator: 0, denominator: 1.
  • More and more digits before the decimal point give you a smaller and smaller denominator until it reaches 1. After that, you get None.

I wondered whether there can be a solution (a fraction) that's so imprecise (not accurately covering enough f64 digits) that "the value cannot be represented by" the Ratio<u32>?


If my description concerning the numerator only is more accurate, maybe your doc comment should also describe it that way to not leave questions open.

Allow usage with summing iterators

It would be useful if you implemented the Sum trait in order to use the .sum() on an iterator over a vec of fractions.
At the moment it fails with the following error:

the trait bound `fraction::fraction::GenericFraction<u64>: std::iter::Sum` is not satisfied
the trait `std::iter::Sum` is not implemented for `fraction::fraction::GenericFraction<u64>`rustc(E0277)

Trait bounds were not satisfied with nalgebra

When I want to use Fraction in nalgebra (a linear algebra library), there are some traits that do not meet the requirements:

fn main() {
    type Fraction = fraction::Fraction;
    type Matrix = nalgebra::Matrix2<Fraction>;

    let a = Matrix::new(
        Fraction::from(1),
        Fraction::from(2),
        Fraction::from(3),
        Fraction::from(4),
    );

    println!("{:.3}", a.try_inverse().unwrap());
}

Error message:

  --> src\main.rs:15:25
   |
15 |     println!("{:.3}", a.try_inverse().unwrap());
   |                         ^^^^^^^^^^^ method cannot be called due to unsatisfied trait bounds
53 | pub enum GenericFraction<T>
   | ---------------------------
   | |
   | doesn't satisfy `<_ as SimdValue>::Element = GenericFraction<u64>`
   | doesn't satisfy `<_ as SimdValue>::SimdBool = bool`
   | doesn't satisfy `GenericFraction<u64>: ComplexField`
   | doesn't satisfy `GenericFraction<u64>: Field`
   | doesn't satisfy `GenericFraction<u64>: FromPrimitive`
   | doesn't satisfy `GenericFraction<u64>: SimdValue`
   | doesn't satisfy `_: SubsetOf<GenericFraction<u64>>`
   | doesn't satisfy `_: SupersetOf<f64>`
   |
   = note: the following trait bounds were not satisfied:
           `GenericFraction<u64>: ComplexField`
           `<GenericFraction<u64> as SimdValue>::SimdBool = bool`
           which is required by `GenericFraction<u64>: ComplexField`
           `<GenericFraction<u64> as SimdValue>::Element = GenericFraction<u64>`
           which is required by `GenericFraction<u64>: ComplexField`
           `GenericFraction<u64>: Field`
           which is required by `GenericFraction<u64>: ComplexField`
           `GenericFraction<u64>: SimdValue`
           which is required by `GenericFraction<u64>: ComplexField`
           `GenericFraction<u64>: FromPrimitive`
           which is required by `GenericFraction<u64>: ComplexField`
           `GenericFraction<u64>: simba::scalar::subset::SupersetOf<f64>`
           which is required by `GenericFraction<u64>: ComplexField`
           `GenericFraction<u64>: simba::scalar::subset::SubsetOf<GenericFraction<u64>>`
           which is required by `GenericFraction<u64>: ComplexField`

Is there any way to solve this problem?

Initialization of Decimal without str?

Hi there,

I was wondering if there were a way to initialize a Decimal without passing through a string formatting?

Looking at the flamegraph of a library which does literally thousands of computations using decimal, the conversion of an f64 into a GenericDecimal<u128, u16> takes 4.16% of the computation time (cf. attachment).

Hence, I was wondering what I could increase the performance. Thanks

Screenshot_20201207_195935

Error: trait bounds other than `Sized` on const fn parameters are unstable

#24 64.60 error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
#24 64.60    --> /usr/local/cargo/registry/src/github.com-1ecc6299db9ec823/fraction-0.12.1/src/fraction/generic_fraction.rs:164:6
#24 64.60     |
#24 64.60 164 | impl<T> GenericFraction<T>
#24 64.60     |      ^
#24 64.60 ...
#24 64.60 275 |     pub const fn new_raw(num: T, den: T) -> GenericFraction<T> {

#24 64.60     |     ---------------------------------------------------------- function declared as const here
#24 64.60     |
#24 64.60     = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information

Deprecate fraction::convert

Now that TryFrom and TryInto are stable, the internal replacement should be deprecated in their favour, as hinted at by the documentation.

Add better unicode support (Fraction slash/division slash)

Since Rust supports full Unicode and because of the name of this crate, I think the fraction slash '⁄' is a better delimiter than the solidus '/' for display purposes. In any case, it should not be an error in parsing to use:

  • Solidus: '/'
  • Fraction slash: '⁄'
  • Division slash: '∕'
  • Division sign: '÷'

Here is a discussion I started on Rust internals. and here is a SO unicode discussion on fractions.

Serde support?

When using decimal to replace is f64/32, some times we need to send the data through network or save them into file. Serde helps a lot. OrderedFloat supports serde. Do you have plan to support it?

panic: attempt to multiply with overflow

I get a panic when I run the following code (with fraction=0.6.2):

use fraction::Decimal;

fn main() {
    let d1 = Decimal::from("0.0002") * Decimal::from("9876.54321");
    let d2 = Decimal::from("51.53023471399515");
    let d3 = d1 + d2;

    println!("{:?} + {:?} = {:?}", d1, d2, d3);
}
$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target/debug/fraction-test`
thread 'main' panicked at 'attempt to multiply with overflow', /rustc/eae3437dfe991621e8afdc82734f4a172d7ddf9b/src/libcore/ops/arith.rs:318:45
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.

no-std support

I need precisely the GenericDecimal type in my (embedded) project but unfortunately I don't have a heap available and fraction links towards std.

Are there any plans to support (a limited set) of this crate for no-std environments?

How should I handle consts?

Hi, I'm adding trigonometric functions as I need them for my project. Since try_into() isn't allowed in consts and I can't think of any other way to do different values for them My current approach is to have a Consts trait with an impl for GeneralFraction, GeneralFraction, GeneralFraction and so on then I made a Trigametric trait which requires the Consts trait.

I currently just have atan() and atan2() you can view my work in the trigonometrics branch of my fork

Zeros store negative

Not sure if it is intended but zeros store negatives inside. When I print a zero fraction I get -0.

Serialization support for DynaInt

Even though I have feature "with-serde-support" on, when I implement a struct or enum that contains DynaInt or any type that uses it and place #[derive(Serialize)] on my type I get:

error: the trait bound DynaInt<u64, BigUint>: Serialize is not satisfied
label: the trait Serialize is not implemented for DynaInt<u64, BigUint>

Serialization seems to work fine for GenericDecimal. I'm fairly new to Rust - is there something I'm doing wrong? Or is there some reason serialization is not supported for DynaInt?

Why is zero() not equal to neg_zero()?

Pretty simple to reproduce: assert_eq!(BigFraction::zero(), BigFraction::neg_zero());

Well, this is kind of annoying. One of the advantages of Fractions over floating point is that you can do exact comparisons. But now we have an edge case that we have to handle before each comparison. I don't see any reason for this being desired behavior.

.pow() and .root() functions for fraction types

I'm currently writing a basic calculator with this library and I noticed at the moment there is no .pow() or .root() style functions for fractions.

Also when performing square roots should they simply be approximated or should numbers simply represent simplified square roots, popping all of the irrational roots in a vector or something like that. For example, something like this

let foo = Fraction::from(75u32);
let result = foo.sqrt();
assert_eq!(5, result.get_base_multiplicand()); // Not actually functional code just here to get a point across
assert_eq!(3, result.get_root_multipliers()[0]);
println!("{:9}", result); // -> 8.660254037

I would like to contribute I'm just unsure how as to go about tackling this problem, at the moment

Missing Clone bound causes compilation of 0.3.5 to fail

   Compiling fraction v0.3.5
error[E0277]: the trait bound `T: std::clone::Clone` is not satisfied
   --> /Users/thill/.cargo/registry/src/github.com-1ecc6299db9ec823/fraction-0.3.5/src/lib.rs:149:21
    |
149 |     Rational (Sign, Ratio<T>),
    |                     ^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `T`
    |
    = help: consider adding a `where T: std::clone::Clone` bound
    = note: required because of the requirements on the impl of `std::hash::Hash` for `num::rational::Ratio<T>`
    = note: required by `std::hash::Hash::hash`

error[E0277]: the trait bound `T: num::Integer` is not satisfied
   --> /Users/thill/.cargo/registry/src/github.com-1ecc6299db9ec823/fraction-0.3.5/src/lib.rs:149:21
    |
149 |     Rational (Sign, Ratio<T>),
    |                     ^^^^^^^^^ the trait `num::Integer` is not implemented for `T`
    |
    = help: consider adding a `where T: num::Integer` bound
    = note: required because of the requirements on the impl of `std::hash::Hash` for `num::rational::Ratio<T>`
    = note: required by `std::hash::Hash::hash`

error: aborting due to previous error(s)
error: Could not compile `fraction`.
Build failed, waiting for other jobs to finish...
error: build failed

Fraction::from_str can fail with overflow if fractional part ends with too many zeroes

Fraction::from_str("10000000000000.0000000000").unwrap() will fail with overflow error while it can be represented without loss.

The from_str implementation use the number of digits to guard against overflow, but in this case, the fractional part trailing 0 should not be counted.

This issue arise easily when using bigdecimal::BigDecimal::to_string as input of Fraction::from_str (conversion between bigdecimal and fraction may looks strange, but bigdecimal is better supported by postgresql while some code use Fraction for computation).

`divide_to_string` panics on negative dividend

Using version 0.8.0, this testcase panics:

    #[test]
    fn divide() {
        fraction::division::divide_to_string(-1, 1, 10, false);
    }

Panic:

thread 'tests::divide' panicked at 'internal error: entered unreachable code', C:.cargo\registry\src\github.com-1ecc6299db9ec823\fraction-0.8.0\src\division.rs:350:21

Expose Num traits

it could be helpful to expose num crate traits through fraction so that we could use its functionality without explicit dependency on num crate in other packages. (e.g. from_str_radix requires Num trait).

Add support for ruint?

Curious if you'd be open to a PR adding support for ruint in fraction and decimal as a num-bigint alternative. I think the constraints would all work. ruint supports conversions into num-bigint, but having native support would be nice.

FromStr trait support + Parse fractions

It looks like the fraction library doesn't support parsing fractions in the format of 1/2. I wrote a toy Postgres type (https://github.com/scott-wilson/pg_fraction), and I'd like to move converting the fraction to this crate.

If this is not currently supported, then I suggest adding support for FromStr::from_str. Also, I recommend using nom for parsing the string, since it makes parsing strings fairly easy (see https://github.com/scott-wilson/pg_fraction/blob/e799ca9102a7f34b7a7d3241a5fcfda4a7b2be57/src/lib.rs#L31)

I'll happy set up a PR to add support for parsing fractions, and also to use nom for parsing (including updating GenericFraction::from_decimal_str to the new parser). Let me know if this is something for me to tackle, and I'll start on it this week.

cargo check: Trait objects without an explicit `dyn` are deprecated

cargo check is complaining,

warning: trait objects without an explicit `dyn` are deprecated
   --> src/division.rs:542:21
    |
542 |     writeable: &mut Write,
    |                     ^^^^^ help: use `dyn`: `dyn Write`
    |
    = note: `#[warn(bare_trait_objects)]` on by default

warning: trait objects without an explicit `dyn` are deprecated
   --> src/division.rs:756:36
    |
756 | pub fn write_digit(writeable: &mut Write, digit: u8) -> Result<bool, DivisionError>
    |                                    ^^^^^ help: use `dyn`: `dyn Write`

warning: trait objects without an explicit `dyn` are deprecated
  --> src/error.rs:56:23
   |
56 |     ExternalError(Box<Error + Send + Sync>)
   |                       ^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn Error + Send + Sync`

warning: trait objects without an explicit `dyn` are deprecated
   --> src/fraction/display.rs:192:45
    |
192 | pub fn format_sign(sign: Sign, buffer: &mut fmt::Write, format: &Format) -> fmt::Result {
    |                                             ^^^^^^^^^^ help: use `dyn`: `dyn fmt::Write`

warning: trait objects without an explicit `dyn` are deprecated
   --> src/fraction/display.rs:225:18
    |
225 |     buffer: &mut fmt::Write,
    |                  ^^^^^^^^^^ help: use `dyn`: `dyn fmt::Write`

warning: trait objects without an explicit `dyn` are deprecated
   --> src/fraction/display.rs:351:20
    |
351 |     V: FnOnce(&mut fmt::Write, &Format) -> Result<usize, fmt::Error>,
    |                    ^^^^^^^^^^ help: use `dyn`: `dyn fmt::Write`

warning: trait objects without an explicit `dyn` are deprecated
   --> src/fraction/display.rs:343:18
    |
343 |     buffer: &mut fmt::Write,
    |                  ^^^^^^^^^^ help: use `dyn`: `dyn fmt::Write`

    Finished dev [unoptimized + debuginfo] target(s) in 0.13s

I am not sure if it will break anything, but its quite a simple fix.

Fraction ceil and floor round negative fraction "the wrong way"

Fraction::floor rounds negative Fractions upwards (towards zero), and Fraction::ceil rounds negative fractions towards negative infinity. Since the docs says that floor should "Returns the largest integer less than or equal to the value" I'm assuming this is unintentional

let f = Fraction::new_neg(1u8, 2u8);
println!("{} {}", f.floor(), f.ceil());

This example prints -0 -1 when the output should be -1 -0

Weird huge values when getting the denominator of a fraction

Hi.

I can into this while working on a chemical equation balancer, this may be a bug, or it might be something I'm going wrong.

I've gotten all of the matrix stuff done, and it yields a set of coefficients. The ones in my example are as follows: [-0.5, -0.33333334, -0.16666667, 1.0].

I create a fraction from these numbers, as follows:

let f = Fraction::from(*coeff);
if let Some(d) = f.denom() {
    denoms.push(*d as f32);
} else {
    panic!("Unable to obtain a valid denominator.");
}

Which should be correct, I believe.

The code produces a list of denominators as follows: [2.0, 50000000.0, 100000000.0, 1.0]

The first and last entries look fine, but there definitely appears to be something wrong with the other two entries. If this isn't a bug, then what am I doing wrong here and how can I fix it?

Thanks in advance.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.