Skip to content

Commit 458ead0

Browse files
Merge pull request RustPython#600 from adrian17/as_ratio
Add float.as_integer_ratio()
2 parents 883a494 + eed0b3c commit 458ead0

File tree

4 files changed

+58
-0
lines changed

4 files changed

+58
-0
lines changed

Cargo.lock

+12
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/snippets/floats.py

+19
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,22 @@
8787
assert (1.7).real == 1.7
8888
assert (1.3).is_integer() == False
8989
assert (1.0).is_integer() == True
90+
91+
assert (0.875).as_integer_ratio() == (7, 8)
92+
assert (-0.875).as_integer_ratio() == (-7, 8)
93+
assert (0.0).as_integer_ratio() == (0, 1)
94+
assert (11.5).as_integer_ratio() == (23, 2)
95+
assert (0.0).as_integer_ratio() == (0, 1)
96+
assert (2.5).as_integer_ratio() == (5, 2)
97+
assert (0.5).as_integer_ratio() == (1, 2)
98+
assert (2.1).as_integer_ratio() == (4728779608739021, 2251799813685248)
99+
assert (-2.1).as_integer_ratio() == (-4728779608739021, 2251799813685248)
100+
assert (-2100.0).as_integer_ratio() == (-2100, 1)
101+
assert (2.220446049250313e-16).as_integer_ratio() == (1, 4503599627370496)
102+
assert (1.7976931348623157e+308).as_integer_ratio() == (179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368, 1)
103+
assert (2.2250738585072014e-308).as_integer_ratio() == (1, 44942328371557897693232629769725618340449424473557664318357520289433168951375240783177119330601884005280028469967848339414697442203604155623211857659868531094441973356216371319075554900311523529863270738021251442209537670585615720368478277635206809290837627671146574559986811484619929076208839082406056034304)
104+
105+
assert_raises(OverflowError, float('inf').as_integer_ratio)
106+
assert_raises(OverflowError, float('-inf').as_integer_ratio)
107+
assert_raises(ValueError, float('nan').as_integer_ratio)
108+

vm/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ num-complex = "0.2"
1010
num-bigint = "0.2.1"
1111
num-traits = "0.2"
1212
num-integer = "0.1.39"
13+
num-rational = "0.2.1"
1314
rand = "0.5"
1415
log = "0.3"
1516
rustpython_parser = {path = "../parser"}

vm/src/obj/objfloat.rs

+26
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ use super::objbytes;
22
use super::objint;
33
use super::objstr;
44
use super::objtype;
5+
use crate::function::PyRef;
56
use crate::pyobject::{
67
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectPayload2, PyObjectRef, PyResult,
78
TypeProtocol,
89
};
910
use crate::vm::VirtualMachine;
1011
use num_bigint::ToBigInt;
12+
use num_rational::Ratio;
1113
use num_traits::ToPrimitive;
1214

1315
#[derive(Debug, Copy, Clone, PartialEq)]
@@ -27,6 +29,25 @@ impl From<f64> for PyFloat {
2729
}
2830
}
2931

32+
impl PyFloat {
33+
fn as_integer_ratio(zelf: PyRef<Self>, vm: &mut VirtualMachine) -> PyResult {
34+
let value = zelf.value;
35+
if value.is_infinite() {
36+
return Err(
37+
vm.new_overflow_error("cannot convert Infinity to integer ratio".to_string())
38+
);
39+
}
40+
if value.is_nan() {
41+
return Err(vm.new_value_error("cannot convert NaN to integer ratio".to_string()));
42+
}
43+
44+
let ratio = Ratio::from_float(value).unwrap();
45+
let numer = vm.ctx.new_int(ratio.numer().clone());
46+
let denom = vm.ctx.new_int(ratio.denom().clone());
47+
Ok(vm.ctx.new_tuple(vec![numer, denom]))
48+
}
49+
}
50+
3051
fn float_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
3152
arg_check!(vm, args, required = [(float, Some(vm.ctx.float_type()))]);
3253
let v = get_value(float);
@@ -494,4 +515,9 @@ pub fn init(context: &PyContext) {
494515
"is_integer",
495516
context.new_rustfunc(float_is_integer),
496517
);
518+
context.set_attr(
519+
&float_type,
520+
"as_integer_ratio",
521+
context.new_rustfunc(PyFloat::as_integer_ratio),
522+
);
497523
}

0 commit comments

Comments
 (0)