如何准确将浮子转换为分数?

发布于 2025-01-29 22:43:44 字数 463 浏览 2 评论 0原文

我正在搜索如何将浮子转换为最简单的分数,该分数将转换回它并找到这个答案

问题是,给出的Python实现依赖于python标准库中的as_integer_ratio设施,该设施在Rust中不存在。我在评论中问了有关f64 :: frexp的问题,但我不确定我是否理解它的工作原理,因为它的文档非常神秘(至少对我来说):

将数字分解为归一分的分数和基本2指数,令人满意:
self = x * 2^exp
0.5< = abs(x)< 1.0

,最重要的是,这是一个不稳定的功能。

我应该怎么办?

I was searching how to convert a float to the simplest fraction that would convert back to it and found this answer.

Problem is, the Python implementation given relies on the as_integer_ratio facility in the python standard library, which isn't present in Rust. I asked about this in a comment and found out about f64::frexp but I'm not sure I understand how it works, as its documentation is quite cryptic (to me at least):

Breaks the number into a normalized fraction and a base-2 exponent, satisfying:
self = x * 2^exp
0.5 <= abs(x) < 1.0

And on top of that, it's an unstable feature.

What should I do?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

幼儿园老大 2025-02-05 22:43:44

关于浮动到分数转换的复杂之处在于,所有浮子已经具有两个两个分母的理性,但这可能并不是那么有用。您正在寻找的是“ nofollow noreferrer”>“最佳理性近似”某些最大分母内的目标浮点值。

该算法(链接中描述)在其背后有一些巧妙的持续分数数学,但并不难输入代码。这是一个实现它的小型C库:

示例使用:

#include "number_util.h"

int numerator;
int denominator;
RationalApproximation(M_PI, 1000000, NULL, &numerator, &denominator);
printf("%d/%d\n", numerator, denominator); 
// Prints: 3126535/995207 (= 3.14159265...)

希望这是直接用于端口或包装以供其他语言使用。

The complicated thing about float-to-fraction conversion is that all floats are already rationals with a power-of-two denominator, but that probably isn't so useful. What you are looking for is "best rational approximation", to find the closest rational to a target float value within some max denominator.

The algorithm (described in the link) has some clever continued fractions math behind it, but not too difficult to put into code. Here is a small C library that implements it:

Example use:

#include "number_util.h"

int numerator;
int denominator;
RationalApproximation(M_PI, 1000000, NULL, &numerator, &denominator);
printf("%d/%d\n", numerator, denominator); 
// Prints: 3126535/995207 (= 3.14159265...)

This is hopefully straightforward to port or wrap for use in other languages.

半步萧音过轻尘 2025-02-05 22:43:44

除了算法,我想最简单的方法是使用已经有效的东西,例如 分数 板条板:

源自

use std::str::FromStr;
use fraction::{Fraction, Sign};  // choose the type accordingly with your needs (see prelude module docs)

fn main() {
    // There are several ways to construct a fraction, depending on your use case

    let f = Fraction::new(1u8, 2u8);  // constructs with numerator/denominator and normalizes the fraction (finds least common denominator)
    assert_eq!(f, Fraction::new_generic(Sign::Plus, 1i32, 2u8).unwrap());  // with numerator/denominator of different integer types
    assert_eq!(f, Fraction::from(0.5));  // convert from float (f32, f64)
    assert_eq!(f, Fraction::from_str("0.5").unwrap());  // parse a string

    // Raw construct with no extra calculations.
    // Most performant, but does not look for common denominator and may lead to unexpected results
    // in following calculations. Only use if you are sure numerator/denominator are already normalized.
    assert_eq!(f, Fraction::new_raw(1u64, 2u64));
}

Algorithm apart, I guess the easiest way would be to use something working already, like the fraction crate:

From the example

use std::str::FromStr;
use fraction::{Fraction, Sign};  // choose the type accordingly with your needs (see prelude module docs)

fn main() {
    // There are several ways to construct a fraction, depending on your use case

    let f = Fraction::new(1u8, 2u8);  // constructs with numerator/denominator and normalizes the fraction (finds least common denominator)
    assert_eq!(f, Fraction::new_generic(Sign::Plus, 1i32, 2u8).unwrap());  // with numerator/denominator of different integer types
    assert_eq!(f, Fraction::from(0.5));  // convert from float (f32, f64)
    assert_eq!(f, Fraction::from_str("0.5").unwrap());  // parse a string

    // Raw construct with no extra calculations.
    // Most performant, but does not look for common denominator and may lead to unexpected results
    // in following calculations. Only use if you are sure numerator/denominator are already normalized.
    assert_eq!(f, Fraction::new_raw(1u64, 2u64));
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文