class Rational
Eine rationale Zahl kann als ein Paar von Ganzzahlen dargestellt werden: a/b (b>0), wobei a der Zähler und b der Nenner ist. Integer a entspricht mathematisch der rationalen Zahl a/1.
Sie können ein Rational-Objekt explizit erstellen mit
-
Einem rationalen Literal.
Sie können bestimmte Objekte mit konvertieren
-
der Methode
Rational.
Beispiele
Rational(1) #=> (1/1) Rational(2, 3) #=> (2/3) Rational(4, -6) #=> (-2/3) # Reduced. 3.to_r #=> (3/1) 2/3r #=> (2/3)
Sie können auch rationale Objekte aus Gleitkommazahlen oder Zeichenketten erstellen.
Rational(0.3) #=> (5404319552844595/18014398509481984) Rational('0.3') #=> (3/10) Rational('2/3') #=> (2/3) 0.3.to_r #=> (5404319552844595/18014398509481984) '0.3'.to_r #=> (3/10) '2/3'.to_r #=> (2/3) 0.3.rationalize #=> (3/10)
Ein Rational-Objekt ist eine exakte Zahl, die Ihnen hilft, Programme ohne Rundungsfehler zu schreiben.
10.times.inject(0) {|t| t + 0.1 } #=> 0.9999999999999999 10.times.inject(0) {|t| t + Rational('0.1') } #=> (1/1)
Wenn ein Ausdruck jedoch eine ungenaue Komponente (numerischer Wert oder Operation) enthält, erzeugt er ein ungenaues Ergebnis.
Rational(10) / 3 #=> (10/3) Rational(10) / 3.0 #=> 3.3333333333333335 Rational(-8) ** Rational(1, 3) #=> (1.0000000000000002+1.7320508075688772i)
Öffentliche Klassenmethoden
Source
# File ext/json/lib/json/add/rational.rb, line 9 def self.json_create(object) Rational(object['n'], object['d']) end
Siehe as_json.
Öffentliche Instanzmethoden
Source
VALUE
rb_rational_mul(VALUE self, VALUE other)
{
if (RB_INTEGER_TYPE_P(other)) {
{
get_dat1(self);
return f_muldiv(self,
dat->num, dat->den,
other, ONE, '*');
}
}
else if (RB_FLOAT_TYPE_P(other)) {
return DBL2NUM(nurat_to_double(self) * RFLOAT_VALUE(other));
}
else if (RB_TYPE_P(other, T_RATIONAL)) {
{
get_dat2(self, other);
return f_muldiv(self,
adat->num, adat->den,
bdat->num, bdat->den, '*');
}
}
else {
return rb_num_coerce_bin(self, other, '*');
}
}
Gibt das numerische Produkt von self und other zurück.
Rational(9, 8) * 4 #=> (9/2) Rational(20, 9) * 9.8 #=> 21.77777777777778 Rational(9, 8) * Complex(1, 2) # => ((9/8)+(9/4)*i) Rational(2, 3) * Rational(2, 3) #=> (4/9) Rational(900) * Rational(1) #=> (900/1) Rational(-2, 9) * Rational(-9, 2) #=> (1/1)
Source
VALUE
rb_rational_pow(VALUE self, VALUE other)
{
if (k_numeric_p(other) && k_exact_zero_p(other))
return f_rational_new_bang1(CLASS_OF(self), ONE);
if (k_rational_p(other)) {
get_dat1(other);
if (f_one_p(dat->den))
other = dat->num; /* c14n */
}
/* Deal with special cases of 0**n and 1**n */
if (k_numeric_p(other) && k_exact_p(other)) {
get_dat1(self);
if (f_one_p(dat->den)) {
if (f_one_p(dat->num)) {
return f_rational_new_bang1(CLASS_OF(self), ONE);
}
else if (f_minus_one_p(dat->num) && RB_INTEGER_TYPE_P(other)) {
return f_rational_new_bang1(CLASS_OF(self), INT2FIX(rb_int_odd_p(other) ? -1 : 1));
}
else if (INT_ZERO_P(dat->num)) {
if (rb_num_negative_p(other)) {
rb_num_zerodiv();
}
else {
return f_rational_new_bang1(CLASS_OF(self), ZERO);
}
}
}
}
/* General case */
if (FIXNUM_P(other)) {
{
VALUE num, den;
get_dat1(self);
if (INT_POSITIVE_P(other)) {
num = rb_int_pow(dat->num, other);
den = rb_int_pow(dat->den, other);
}
else if (INT_NEGATIVE_P(other)) {
num = rb_int_pow(dat->den, rb_int_uminus(other));
den = rb_int_pow(dat->num, rb_int_uminus(other));
}
else {
num = ONE;
den = ONE;
}
if (RB_FLOAT_TYPE_P(num)) { /* infinity due to overflow */
if (RB_FLOAT_TYPE_P(den))
return DBL2NUM(nan(""));
return num;
}
if (RB_FLOAT_TYPE_P(den)) { /* infinity due to overflow */
num = ZERO;
den = ONE;
}
return f_rational_new2(CLASS_OF(self), num, den);
}
}
else if (RB_BIGNUM_TYPE_P(other)) {
rb_raise(rb_eArgError, "exponent is too large");
}
else if (RB_FLOAT_TYPE_P(other) || RB_TYPE_P(other, T_RATIONAL)) {
return rb_float_pow(nurat_to_f(self), other);
}
else {
return rb_num_coerce_bin(self, other, idPow);
}
}
Gibt self hoch exponent zurück.
Rational(2) ** Rational(3) #=> (8/1) Rational(10) ** -2 #=> (1/100) Rational(10) ** -2.0 #=> 0.01 Rational(-4) ** Rational(1, 2) #=> (0.0+2.0i) Rational(1, 2) ** 0 #=> (1/1) Rational(1, 2) ** 0.0 #=> 1.0
Source
VALUE
rb_rational_plus(VALUE self, VALUE other)
{
if (RB_INTEGER_TYPE_P(other)) {
{
get_dat1(self);
return f_rational_new_no_reduce2(CLASS_OF(self),
rb_int_plus(dat->num, rb_int_mul(other, dat->den)),
dat->den);
}
}
else if (RB_FLOAT_TYPE_P(other)) {
return DBL2NUM(nurat_to_double(self) + RFLOAT_VALUE(other));
}
else if (RB_TYPE_P(other, T_RATIONAL)) {
{
get_dat2(self, other);
return f_addsub(self,
adat->num, adat->den,
bdat->num, bdat->den, '+');
}
}
else {
return rb_num_coerce_bin(self, other, '+');
}
}
Gibt die Summe von self und other zurück.
Rational(2, 3) + 0 # => (2/3) Rational(2, 3) + 1 # => (5/3) Rational(2, 3) + -1 # => (-1/3) Rational(2, 3) + Complex(1, 0) # => ((5/3)+0i) Rational(2, 3) + Rational(1, 1) # => (5/3) Rational(2, 3) + Rational(3, 2) # => (13/6) Rational(2, 3) + Rational(3.0, 2.0) # => (13/6) Rational(2, 3) + Rational(3.1, 2.1) # => (30399297484750849/14186338826217063)
Bei einer Berechnung mit Floats kann das Ergebnis ungenau sein (siehe Float#+).
Rational(2, 3) + 1.0 # => 1.6666666666666665 Rational(2, 3) + Complex(1.0, 0.0) # => (1.6666666666666665+0.0i)
Source
VALUE
rb_rational_minus(VALUE self, VALUE other)
{
if (RB_INTEGER_TYPE_P(other)) {
{
get_dat1(self);
return f_rational_new_no_reduce2(CLASS_OF(self),
rb_int_minus(dat->num, rb_int_mul(other, dat->den)),
dat->den);
}
}
else if (RB_FLOAT_TYPE_P(other)) {
return DBL2NUM(nurat_to_double(self) - RFLOAT_VALUE(other));
}
else if (RB_TYPE_P(other, T_RATIONAL)) {
{
get_dat2(self, other);
return f_addsub(self,
adat->num, adat->den,
bdat->num, bdat->den, '-');
}
}
else {
return rb_num_coerce_bin(self, other, '-');
}
}
Gibt die Differenz von self und other zurück.
Rational(2, 3) - Rational(2, 3) #=> (0/1) Rational(900) - Rational(1) #=> (899/1) Rational(-2, 9) - Rational(-9, 2) #=> (77/18) Rational(9, 8) - 4 #=> (-23/8) Rational(20, 9) - 9.8 #=> -7.577777777777778
Source
VALUE
rb_rational_uminus(VALUE self)
{
const int unused = (RUBY_ASSERT(RB_TYPE_P(self, T_RATIONAL)), 0);
get_dat1(self);
(void)unused;
return f_rational_new2(CLASS_OF(self), rb_int_uminus(dat->num), dat->den);
}
Gibt self, negiert, zurück.
-(1/3r) # => (-1/3) -(-1/3r) # => (1/3)
Source
VALUE
rb_rational_div(VALUE self, VALUE other)
{
if (RB_INTEGER_TYPE_P(other)) {
if (f_zero_p(other))
rb_num_zerodiv();
{
get_dat1(self);
return f_muldiv(self,
dat->num, dat->den,
other, ONE, '/');
}
}
else if (RB_FLOAT_TYPE_P(other)) {
VALUE v = nurat_to_f(self);
return rb_flo_div_flo(v, other);
}
else if (RB_TYPE_P(other, T_RATIONAL)) {
if (f_zero_p(other))
rb_num_zerodiv();
{
get_dat2(self, other);
if (f_one_p(self))
return f_rational_new_no_reduce2(CLASS_OF(self),
bdat->den, bdat->num);
return f_muldiv(self,
adat->num, adat->den,
bdat->num, bdat->den, '/');
}
}
else {
return rb_num_coerce_bin(self, other, '/');
}
}
Gibt den Quotienten von self und other zurück.
Rational(2, 3) / Rational(2, 3) #=> (1/1) Rational(900) / Rational(1) #=> (900/1) Rational(-2, 9) / Rational(-9, 2) #=> (4/81) Rational(9, 8) / 4 #=> (9/32) Rational(20, 9) / 9.8 #=> 0.22675736961451246
Source
VALUE
rb_rational_cmp(VALUE self, VALUE other)
{
switch (TYPE(other)) {
case T_FIXNUM:
case T_BIGNUM:
{
get_dat1(self);
if (dat->den == LONG2FIX(1))
return rb_int_cmp(dat->num, other); /* c14n */
other = f_rational_new_bang1(CLASS_OF(self), other);
/* FALLTHROUGH */
}
case T_RATIONAL:
{
VALUE num1, num2;
get_dat2(self, other);
if (FIXNUM_P(adat->num) && FIXNUM_P(adat->den) &&
FIXNUM_P(bdat->num) && FIXNUM_P(bdat->den)) {
num1 = f_imul(FIX2LONG(adat->num), FIX2LONG(bdat->den));
num2 = f_imul(FIX2LONG(bdat->num), FIX2LONG(adat->den));
}
else {
num1 = rb_int_mul(adat->num, bdat->den);
num2 = rb_int_mul(bdat->num, adat->den);
}
return rb_int_cmp(rb_int_minus(num1, num2), ZERO);
}
case T_FLOAT:
return rb_dbl_cmp(nurat_to_double(self), RFLOAT_VALUE(other));
default:
return rb_num_coerce_cmp(self, other, idCmp);
}
}
Vergleicht self und other.
Gibt zurück
-
-1, wennselfkleiner alsotherist. -
0, wenn die beiden Werte gleich sind. -
1, wennselfgrößer alsotherist. -
nil, wenn die beiden Werte nicht vergleichbar sind.
Beispiele
Rational(2, 3) <=> Rational(4, 3) # => -1 Rational(2, 1) <=> Rational(2, 1) # => 0 Rational(2, 1) <=> 2 # => 0 Rational(2, 1) <=> 2.0 # => 0 Rational(2, 1) <=> Complex(2, 0) # => 0 Rational(4, 3) <=> Rational(2, 3) # => 1 Rational(4, 3) <=> :foo # => nil
Die Klasse Rational enthält das Modul Comparable, dessen Methoden Rational#<=> für den Vergleich verwenden.
Source
static VALUE
nurat_eqeq_p(VALUE self, VALUE other)
{
if (RB_INTEGER_TYPE_P(other)) {
get_dat1(self);
if (RB_INTEGER_TYPE_P(dat->num) && RB_INTEGER_TYPE_P(dat->den)) {
if (INT_ZERO_P(dat->num) && INT_ZERO_P(other))
return Qtrue;
if (!FIXNUM_P(dat->den))
return Qfalse;
if (FIX2LONG(dat->den) != 1)
return Qfalse;
return rb_int_equal(dat->num, other);
}
else {
const double d = nurat_to_double(self);
return RBOOL(FIXNUM_ZERO_P(rb_dbl_cmp(d, NUM2DBL(other))));
}
}
else if (RB_FLOAT_TYPE_P(other)) {
const double d = nurat_to_double(self);
return RBOOL(FIXNUM_ZERO_P(rb_dbl_cmp(d, RFLOAT_VALUE(other))));
}
else if (RB_TYPE_P(other, T_RATIONAL)) {
{
get_dat2(self, other);
if (INT_ZERO_P(adat->num) && INT_ZERO_P(bdat->num))
return Qtrue;
return RBOOL(rb_int_equal(adat->num, bdat->num) &&
rb_int_equal(adat->den, bdat->den));
}
}
else {
return rb_equal(other, self);
}
}
Gibt true zurück, wenn rat numerisch gleich object ist.
Rational(2, 3) == Rational(2, 3) #=> true Rational(5) == 5 #=> true Rational(0) == 0.0 #=> true Rational('1/3') == 0.33 #=> false Rational('1/2') == '1/2' #=> false
Source
VALUE
rb_rational_abs(VALUE self)
{
get_dat1(self);
if (INT_NEGATIVE_P(dat->num)) {
VALUE num = rb_int_abs(dat->num);
return nurat_s_canonicalize_internal_no_reduce(CLASS_OF(self), num, dat->den);
}
return self;
}
Gibt den Absolutwert von rat zurück.
(1/2r).abs #=> (1/2) (-1/2r).abs #=> (1/2)
Source
# File ext/json/lib/json/add/rational.rb, line 29 def as_json(*) { JSON.create_id => self.class.name, 'n' => numerator, 'd' => denominator, } end
Die Methoden Rational#as_json und Rational.json_create können zum Serialisieren und Deserialisieren eines Rational-Objekts verwendet werden; siehe Marshal.
Die Methode Rational#as_json serialisiert self und gibt einen 2-elementigen Hash zurück, der self repräsentiert.
require 'json/add/rational' x = Rational(2, 3).as_json # => {"json_class"=>"Rational", "n"=>2, "d"=>3}
Die Methode JSON.create deserialisiert einen solchen Hash und gibt ein Rational-Objekt zurück.
Rational.json_create(x) # => (2/3)
Source
static VALUE
nurat_ceil_n(int argc, VALUE *argv, VALUE self)
{
return f_round_common(argc, argv, self, nurat_ceil);
}
Gibt die kleinste Zahl zurück, die größer oder gleich rat ist, mit einer Genauigkeit von ndigits Dezimalstellen (Standard: 0).
Wenn die Genauigkeit negativ ist, ist der zurückgegebene Wert eine Ganzzahl mit mindestens ndigits.abs nachfolgenden Nullen.
Gibt eine rationale Zahl zurück, wenn ndigits positiv ist, andernfalls eine Ganzzahl.
Rational(3).ceil #=> 3 Rational(2, 3).ceil #=> 1 Rational(-3, 2).ceil #=> -1 # decimal - 1 2 3 . 4 5 6 # ^ ^ ^ ^ ^ ^ # precision -3 -2 -1 0 +1 +2 Rational('-123.456').ceil(+1).to_f #=> -123.4 Rational('-123.456').ceil(-1) #=> -120
Source
static VALUE
nurat_denominator(VALUE self)
{
get_dat1(self);
return dat->den;
}
Gibt den Nenner zurück (immer positiv).
Rational(7).denominator #=> 1 Rational(7, 1).denominator #=> 1 Rational(9, -4).denominator #=> 4 Rational(-2, -10).denominator #=> 5
Source
static VALUE
nurat_fdiv(VALUE self, VALUE other)
{
VALUE div;
if (f_zero_p(other))
return rb_rational_div(self, rb_float_new(0.0));
if (FIXNUM_P(other) && other == LONG2FIX(1))
return nurat_to_f(self);
div = rb_rational_div(self, other);
if (RB_TYPE_P(div, T_RATIONAL))
return nurat_to_f(div);
if (RB_FLOAT_TYPE_P(div))
return div;
return rb_funcall(div, idTo_f, 0);
}
Führt die Division durch und gibt den Wert als Float zurück.
Rational(2, 3).fdiv(1) #=> 0.6666666666666666 Rational(2, 3).fdiv(0.5) #=> 1.3333333333333333 Rational(2).fdiv(3) #=> 0.6666666666666666
Source
static VALUE
nurat_floor_n(int argc, VALUE *argv, VALUE self)
{
return f_round_common(argc, argv, self, nurat_floor);
}
Gibt die größte Zahl zurück, die kleiner oder gleich rat ist, mit einer Genauigkeit von ndigits Dezimalstellen (Standard: 0).
Wenn die Genauigkeit negativ ist, ist der zurückgegebene Wert eine Ganzzahl mit mindestens ndigits.abs nachfolgenden Nullen.
Gibt eine rationale Zahl zurück, wenn ndigits positiv ist, andernfalls eine Ganzzahl.
Rational(3).floor #=> 3 Rational(2, 3).floor #=> 0 Rational(-3, 2).floor #=> -2 # decimal - 1 2 3 . 4 5 6 # ^ ^ ^ ^ ^ ^ # precision -3 -2 -1 0 +1 +2 Rational('-123.456').floor(+1).to_f #=> -123.5 Rational('-123.456').floor(-1) #=> -130
Source
static VALUE
nurat_inspect(VALUE self)
{
VALUE s;
s = rb_usascii_str_new2("(");
rb_str_concat(s, f_format(self, f_inspect));
rb_str_cat2(s, ")");
return s;
}
Gibt den Wert als Zeichenkette zur Inspektion zurück.
Rational(2).inspect #=> "(2/1)" Rational(-8, 6).inspect #=> "(-4/3)" Rational('1/2').inspect #=> "(1/2)"
Gibt den Absolutwert von rat zurück.
(1/2r).abs #=> (1/2) (-1/2r).abs #=> (1/2)
Source
static VALUE
nurat_negative_p(VALUE self)
{
get_dat1(self);
return RBOOL(INT_NEGATIVE_P(dat->num));
}
Gibt true zurück, wenn rat kleiner als 0 ist.
Source
static VALUE
nurat_numerator(VALUE self)
{
get_dat1(self);
return dat->num;
}
Gibt den Zähler zurück.
Rational(7).numerator #=> 7 Rational(7, 1).numerator #=> 7 Rational(9, -4).numerator #=> -9 Rational(-2, -10).numerator #=> 1
Source
static VALUE
nurat_positive_p(VALUE self)
{
get_dat1(self);
return RBOOL(INT_POSITIVE_P(dat->num));
}
Gibt true zurück, wenn rat größer als 0 ist.
Source
static VALUE
nurat_rationalize(int argc, VALUE *argv, VALUE self)
{
VALUE e, a, b, p, q;
VALUE rat = self;
get_dat1(self);
if (rb_check_arity(argc, 0, 1) == 0)
return self;
e = f_abs(argv[0]);
if (INT_NEGATIVE_P(dat->num)) {
rat = f_rational_new2(RBASIC_CLASS(self), rb_int_uminus(dat->num), dat->den);
}
a = FIXNUM_ZERO_P(e) ? rat : rb_rational_minus(rat, e);
b = FIXNUM_ZERO_P(e) ? rat : rb_rational_plus(rat, e);
if (f_eqeq_p(a, b))
return self;
nurat_rationalize_internal(a, b, &p, &q);
if (rat != self) {
RATIONAL_SET_NUM(rat, rb_int_uminus(p));
RATIONAL_SET_DEN(rat, q);
return rat;
}
return f_rational_new2(CLASS_OF(self), p, q);
}
Gibt eine einfachere Annäherung des Werts zurück, wenn das optionale Argument eps gegeben ist (rat-|eps| <= Ergebnis <= rat+|eps|), andernfalls self.
r = Rational(5033165, 16777216) r.rationalize #=> (5033165/16777216) r.rationalize(Rational('0.01')) #=> (3/10) r.rationalize(Rational('0.1')) #=> (1/3)
Source
static VALUE
nurat_round_n(int argc, VALUE *argv, VALUE self)
{
VALUE opt;
enum ruby_num_rounding_mode mode = (
argc = rb_scan_args(argc, argv, "*:", NULL, &opt),
rb_num_get_rounding_option(opt));
VALUE (*round_func)(VALUE) = ROUND_FUNC(mode, nurat_round);
return f_round_common(argc, argv, self, round_func);
}
Gibt rat gerundet auf den nächsten Wert mit einer Genauigkeit von ndigits Dezimalstellen zurück (Standard: 0).
Wenn die Genauigkeit negativ ist, ist der zurückgegebene Wert eine Ganzzahl mit mindestens ndigits.abs nachfolgenden Nullen.
Gibt eine rationale Zahl zurück, wenn ndigits positiv ist, andernfalls eine Ganzzahl.
Rational(3).round #=> 3 Rational(2, 3).round #=> 1 Rational(-3, 2).round #=> -2 # decimal - 1 2 3 . 4 5 6 # ^ ^ ^ ^ ^ ^ # precision -3 -2 -1 0 +1 +2 Rational('-123.456').round(+1).to_f #=> -123.5 Rational('-123.456').round(-1) #=> -120
Das optionale Schlüsselwortargument half ist ähnlich wie bei Float#round verfügbar.
Rational(25, 100).round(1, half: :up) #=> (3/10) Rational(25, 100).round(1, half: :down) #=> (1/5) Rational(25, 100).round(1, half: :even) #=> (1/5) Rational(35, 100).round(1, half: :up) #=> (2/5) Rational(35, 100).round(1, half: :down) #=> (3/10) Rational(35, 100).round(1, half: :even) #=> (2/5) Rational(-25, 100).round(1, half: :up) #=> (-3/10) Rational(-25, 100).round(1, half: :down) #=> (-1/5) Rational(-25, 100).round(1, half: :even) #=> (-1/5)
Source
static VALUE
nurat_to_f(VALUE self)
{
return DBL2NUM(nurat_to_double(self));
}
Gibt den Wert als Float zurück.
Rational(2).to_f #=> 2.0 Rational(9, 4).to_f #=> 2.25 Rational(-3, 4).to_f #=> -0.75 Rational(20, 3).to_f #=> 6.666666666666667
Source
static VALUE
nurat_truncate(VALUE self)
{
get_dat1(self);
if (INT_NEGATIVE_P(dat->num))
return rb_int_uminus(rb_int_idiv(rb_int_uminus(dat->num), dat->den));
return rb_int_idiv(dat->num, dat->den);
}
Gibt den abgeschnittenen Wert als Ganzzahl zurück.
Entspricht Rational#truncate.
Rational(2, 3).to_i #=> 0 Rational(3).to_i #=> 3 Rational(300.6).to_i #=> 300 Rational(98, 71).to_i #=> 1 Rational(-31, 2).to_i #=> -15
Source
# File ext/json/lib/json/add/rational.rb, line 46 def to_json(*args) as_json.to_json(*args) end
Gibt einen JSON-String zurück, der self repräsentiert
require 'json/add/rational' puts Rational(2, 3).to_json
Ausgabe
{"json_class":"Rational","n":2,"d":3}
Source
static VALUE
nurat_to_r(VALUE self)
{
return self;
}
Gibt self zurück.
Rational(2).to_r #=> (2/1) Rational(-8, 6).to_r #=> (-4/3)
Source
static VALUE
nurat_to_s(VALUE self)
{
return f_format(self, f_to_s);
}
Gibt den Wert als Zeichenkette zurück.
Rational(2).to_s #=> "2/1" Rational(-8, 6).to_s #=> "-4/3" Rational('1/2').to_s #=> "1/2"
Source
static VALUE
nurat_truncate_n(int argc, VALUE *argv, VALUE self)
{
return f_round_common(argc, argv, self, nurat_truncate);
}
Gibt rat auf eine Genauigkeit von ndigits Dezimalstellen (Standard: 0) gekürzt (in Richtung Null) zurück.
Wenn die Genauigkeit negativ ist, ist der zurückgegebene Wert eine Ganzzahl mit mindestens ndigits.abs nachfolgenden Nullen.
Gibt eine rationale Zahl zurück, wenn ndigits positiv ist, andernfalls eine Ganzzahl.
Rational(3).truncate #=> 3 Rational(2, 3).truncate #=> 0 Rational(-3, 2).truncate #=> -1 # decimal - 1 2 3 . 4 5 6 # ^ ^ ^ ^ ^ ^ # precision -3 -2 -1 0 +1 +2 Rational('-123.456').truncate(+1).to_f #=> -123.4 Rational('-123.456').truncate(-1) #=> -120