Ruby/Float
تمثل كائنات Float أرقامًا حقيقية غير دقيقة باستخدام تمثيل النقطة العائمة المزدوجة الدقة للبنية الأصلية.
للنقطة العائمة حساب مختلف وهو رقم غير دقيق. لذا يجب معرفة نظامها الخاص. انظر التالي:
docs.sun.com/source/806-3568/ncg_goldberg.html
wiki.github.com/rdp/ruby_tutorials_core/ruby-talk-faq#wiki-floats_imprecise
en.wikipedia.org/wiki/Floating_point#Accuracy_problems
الثوابت
DIG
الحد الأدنى لعدد الأرقام العشرية ذات الدلالة في النقطة العائمة المزدوجة الدقة.
وعادة ما تكون قيمته الافتراضية 15
.
EPSILON
الفرق بين 1
و أصغر عدد أكبر من 1
من نوع النقطة العائمة المزدوجة الدقة.
وعادة ما تكون قيمته الافتراضية 2.2204460492503131e-16
.
INFINITY
تعبير يمثل اللانهاية الموجبة.
MANT_DIG
عدد الأرقام الأساسية لنوع البيانات المزدوج (double).
وعادة ما تكون قيمته الافتراضية 53
.
MAX
أكبر عدد صحيح في النقطة العائمة المزدوجة الدقة.
وعادة ما تكون قيمته الافتراضية 1.7976931348623157e+308
.
MAX_10_EXP
أكبر أس موجب في النقطة العائمة المزدوجة الدقة حيث تكون 10
مرفوعة إلى هذا الأس ناقص 1
.
وعادة ما تكون قيمته الافتراضية 308
.
MAX_EXP
أكبر قيمة أس محتملة في النقطة العائمة المزدوجة الدقة.
وعادة ما تكون قيمته الافتراضية 1024
.
MIN
أصغر رقم مُعيَّر موجب في النقطة العائمة المزدوجة الدقة.
وعادة ما تكون قيمته الافتراضية 2.2250738585072014e-308
.
إذا كانت المنصة تدعم الأرقام غير المُعيَّرة، يكون هناك أرقام بين صفر و Float::MIN
. وتعيد 0.0.next_float
أصغر نقطة عائمة موجبة بما في ذلك الأرقام غير المُعيَّرة.
MIN_10_EXP
أصغر أس سالب في النقطة العائمة المزدوجة الدقة حيث تكون 10
مرفوعة إلى هذا الأس ناقص 1
.
وعادة ما تكون قيمته الافتراضية -307
.
MIN_EXP
أصغر قيمة أس محتملة في النقطة العائمة المزدوجة الدقة.
وعادة ما تكون قيمته الافتراضية -1021
.
NAN
تعبير يمثل القيمة "ليست عددًا" (not a number).
RADIX
أساس النقطة العائمة، أو عدد الأرقام الفريدة المستخدمة لتمثيل الرقم.
وعادة ما تكون قيمته الافتراضية 2
على معظم الأنظمة، والتي تمثل النظام العشري للأساس 10
.
ROUNDS
يمثل وضع التقريب لإضافة النقطة العائمة.
وعادة ما تكون قيمته الافتراضية 1
، التقريب إلى أقرب عدد.
وتشمل الأوضاع الأخرى:
-1
: مُتعذِّر تحديده.
0
: التقريب نحو الصفر.
1
: التقريب إلى أقرب عدد.
2
: التقريب نحو اللانهاية الموجبة.
3
: التقريب نحو اللانهاية السالبة.
توابع المثيل العام
float % other → float
إعادة الوحدة بعد قسمة float
على other
.
6543.21.modulo(137) #=> 104.21000000000004
6543.21.modulo(137.24) #=> 92.92999999999961
static VALUE
flo_mod(VALUE x, VALUE y)
{
double fy;
if (RB_TYPE_P(y, T_FIXNUM)) {
fy = (double)FIX2LONG(y);
}
else if (RB_TYPE_P(y, T_BIGNUM)) {
fy = rb_big2dbl(y);
}
else if (RB_TYPE_P(y, T_FLOAT)) {
fy = RFLOAT_VALUE(y);
}
else {
return rb_num_coerce_bin(x, y, '%');
}
return DBL2NUM(ruby_float_mod(RFLOAT_VALUE(x), fy));
}
float * other → float
إعادة Float جديد والذي يكون هو نتاج حاصل ضرب float
و other
.
static VALUE
flo_mul(VALUE x, VALUE y)
{
if (RB_TYPE_P(y, T_FIXNUM)) {
return DBL2NUM(RFLOAT_VALUE(x) * (double)FIX2LONG(y));
}
else if (RB_TYPE_P(y, T_BIGNUM)) {
return DBL2NUM(RFLOAT_VALUE(x) * rb_big2dbl(y));
}
else if (RB_TYPE_P(y, T_FLOAT)) {
return DBL2NUM(RFLOAT_VALUE(x) * RFLOAT_VALUE(y));
}
else {
return rb_num_coerce_bin(x, y, '*');
}
}
float ** other → float
رفع float
للأس other
.
2.0**3 #=> 8.0
VALUE
rb_float_pow(VALUE x, VALUE y)
{
double dx, dy;
if (RB_TYPE_P(y, T_FIXNUM)) {
dx = RFLOAT_VALUE(x);
dy = (double)FIX2LONG(y);
}
else if (RB_TYPE_P(y, T_BIGNUM)) {
dx = RFLOAT_VALUE(x);
dy = rb_big2dbl(y);
}
else if (RB_TYPE_P(y, T_FLOAT)) {
dx = RFLOAT_VALUE(x);
dy = RFLOAT_VALUE(y);
if (dx < 0 && dy != round(dy))
return num_funcall1(rb_complex_raw1(x), idPow, y);
}
else {
return rb_num_coerce_bin(x, y, idPow);
}
return DBL2NUM(pow(dx, dy));
}
float + other → float
إعادة Float جديد والذي يكون هو نتاج حاصل جمع float
و other
.
static VALUE
flo_plus(VALUE x, VALUE y)
{
if (RB_TYPE_P(y, T_FIXNUM)) {
return DBL2NUM(RFLOAT_VALUE(x) + (double)FIX2LONG(y));
}
else if (RB_TYPE_P(y, T_BIGNUM)) {
return DBL2NUM(RFLOAT_VALUE(x) + rb_big2dbl(y));
}
else if (RB_TYPE_P(y, T_FLOAT)) {
return DBL2NUM(RFLOAT_VALUE(x) + RFLOAT_VALUE(y));
}
else {
return rb_num_coerce_bin(x, y, '+');
}
}
float - other → float
إعادة Float جديد والذي يكون هو الفرق بين float
و other
.
static VALUE
flo_minus(VALUE x, VALUE y)
{
if (RB_TYPE_P(y, T_FIXNUM)) {
return DBL2NUM(RFLOAT_VALUE(x) - (double)FIX2LONG(y));
}
else if (RB_TYPE_P(y, T_BIGNUM)) {
return DBL2NUM(RFLOAT_VALUE(x) - rb_big2dbl(y));
}
else if (RB_TYPE_P(y, T_FLOAT)) {
return DBL2NUM(RFLOAT_VALUE(x) - RFLOAT_VALUE(y));
}
else {
return rb_num_coerce_bin(x, y, '-');
}
}
-float → float
إعادة float
بعلامة سالبة.
VALUE
rb_float_uminus(VALUE flt)
{
return DBL2NUM(-RFLOAT_VALUE(flt));
}
float / other → float
إعادة Float جديد والذي يكون نتاج حاصل قسمة float
على other
.
static VALUE
flo_div(VALUE x, VALUE y)
{
long f_y;
double d;
if (RB_TYPE_P(y, T_FIXNUM)) {
f_y = FIX2LONG(y);
return DBL2NUM(RFLOAT_VALUE(x) / (double)f_y);
}
else if (RB_TYPE_P(y, T_BIGNUM)) {
d = rb_big2dbl(y);
return DBL2NUM(RFLOAT_VALUE(x) / d);
}
else if (RB_TYPE_P(y, T_FLOAT)) {
return DBL2NUM(RFLOAT_VALUE(x) / RFLOAT_VALUE(y));
}
else {
return rb_num_coerce_bin(x, y, '/');
}
}
float < real → true or false
إعادة true
إذا كان float
أقل من real
.
نتيجة NaN < NaN غير مُعرَّفة، لذا تُعاد قيمة تعتمد على التنفيذ.
static VALUE
flo_lt(VALUE x, VALUE y)
{
double a, b;
a = RFLOAT_VALUE(x);
if (RB_TYPE_P(y, T_FIXNUM) || RB_TYPE_P(y, T_BIGNUM)) {
VALUE rel = rb_integer_float_cmp(y, x);
if (FIXNUM_P(rel))
return -FIX2INT(rel) < 0 ? Qtrue : Qfalse;
return Qfalse;
}
else if (RB_TYPE_P(y, T_FLOAT)) {
b = RFLOAT_VALUE(y);
#if defined(_MSC_VER) && _MSC_VER < 1300
if (isnan(b)) return Qfalse;
#endif
}
else {
return rb_num_coerce_relop(x, y, '<');
}
#if defined(_MSC_VER) && _MSC_VER < 1300
if (isnan(a)) return Qfalse;
#endif
return (a < b)?Qtrue:Qfalse;
}
float <= real → true or false
إعادة true
إذا كان float
أقل من أو يساوي real
.
نتيجة NaN <= NaN غير معرفة، لذا تُعاد قيمة تعتمد على التنفيذ.
static VALUE
flo_le(VALUE x, VALUE y)
{
double a, b;
a = RFLOAT_VALUE(x);
if (RB_TYPE_P(y, T_FIXNUM) || RB_TYPE_P(y, T_BIGNUM)) {
VALUE rel = rb_integer_float_cmp(y, x);
if (FIXNUM_P(rel))
return -FIX2INT(rel) <= 0 ? Qtrue : Qfalse;
return Qfalse;
}
else if (RB_TYPE_P(y, T_FLOAT)) {
b = RFLOAT_VALUE(y);
#if defined(_MSC_VER) && _MSC_VER < 1300
if (isnan(b)) return Qfalse;
#endif
}
else {
return rb_num_coerce_relop(x, y, idLE);
}
#if defined(_MSC_VER) && _MSC_VER < 1300
if (isnan(a)) return Qfalse;
#endif
return (a <= b)?Qtrue:Qfalse;
}
float <=> real → -1, 0, +1, or nil
إعادة -1 ، 0 أو +1 اعتمادًا على ما إذا كان float
أقل من أو يساوي أو أكبر من real
. هذا هو أساس الاختبارات في وحدة Comparable.
نتيجة NaN <=> NaN غير مُعرَّفة، لذا تُعاد قيمة تعتمد علي التنفيذ.
إعادة nil
إذا كانت القيمتين غير صالحتين للمقارنة.
static VALUE
flo_cmp(VALUE x, VALUE y)
{
double a, b;
VALUE i;
a = RFLOAT_VALUE(x);
if (isnan(a)) return Qnil;
if (RB_TYPE_P(y, T_FIXNUM) || RB_TYPE_P(y, T_BIGNUM)) {
VALUE rel = rb_integer_float_cmp(y, x);
if (FIXNUM_P(rel))
return INT2FIX(-FIX2INT(rel));
return rel;
}
else if (RB_TYPE_P(y, T_FLOAT)) {
b = RFLOAT_VALUE(y);
}
else {
if (isinf(a) && (i = rb_check_funcall(y, rb_intern("infinite?"), 0, 0)) != Qundef) {
if (RTEST(i)) {
int j = rb_cmpint(i, x, y);
j = (a > 0.0) ? (j > 0 ? 0 : +1) : (j < 0 ? 0 : -1);
return INT2FIX(j);
}
if (a > 0.0) return INT2FIX(1);
return INT2FIX(-1);
}
return rb_num_coerce_cmp(x, y, id_cmp);
}
return rb_dbl_cmp(a, b);
}
float == obj → true or false
إعادة true
فقط إذا كانت قيمة obj
نفس قيمة float
. علي عكس ذلك تحتاج #eql?
أن يكون obj
من النوع Float.
1.0 == 1 #=> true
نتيجة NaN == NaN غير مُعرَّفة، لذا تُعاد قيمة تعتمد علي التنفيذ.
VALUE
rb_float_equal(VALUE x, VALUE y)
{
volatile double a, b;
if (RB_TYPE_P(y, T_FIXNUM) || RB_TYPE_P(y, T_BIGNUM)) {
return rb_integer_float_eq(y, x);
}
else if (RB_TYPE_P(y, T_FLOAT)) {
b = RFLOAT_VALUE(y);
#if defined(_MSC_VER) && _MSC_VER < 1300
if (isnan(b)) return Qfalse;
#endif
}
else {
return num_equal(x, y);
}
a = RFLOAT_VALUE(x);
#if defined(_MSC_VER) && _MSC_VER < 1300
if (isnan(a)) return Qfalse;
#endif
return (a == b)?Qtrue:Qfalse;
}
float == obj → true or false
إعادة true
فقط إذا كانت قيمة obj
نفس قيمة float
. علي عكس ذلك تحتاج #eql?
أن يكون obj
من نوع Float.
نتيجة NaN == NaN غير مُعرَّفة، لذا تُعاد قيمة تعتمد علي التنفيذ.
VALUE
rb_float_equal(VALUE x, VALUE y)
{
volatile double a, b;
if (RB_TYPE_P(y, T_FIXNUM) || RB_TYPE_P(y, T_BIGNUM)) {
return rb_integer_float_eq(y, x);
}
else if (RB_TYPE_P(y, T_FLOAT)) {
b = RFLOAT_VALUE(y);
#if defined(_MSC_VER) && _MSC_VER < 1300
if (isnan(b)) return Qfalse;
#endif
}
else {
return num_equal(x, y);
}
a = RFLOAT_VALUE(x);
#if defined(_MSC_VER) && _MSC_VER < 1300
if (isnan(a)) return Qfalse;
#endif
return (a == b)?Qtrue:Qfalse;
}
float > real → true or false
إعادة true
إذا كان float
أكبر من real
.
نتيجة NaN > NaN غير مُعرَّفة، لذا تُعاد قيمة تعتمد علي التنفيذ.
VALUE
rb_float_gt(VALUE x, VALUE y)
{
double a, b;
a = RFLOAT_VALUE(x);
if (RB_TYPE_P(y, T_FIXNUM) || RB_TYPE_P(y, T_BIGNUM)) {
VALUE rel = rb_integer_float_cmp(y, x);
if (FIXNUM_P(rel))
return -FIX2INT(rel) > 0 ? Qtrue : Qfalse;
return Qfalse;
}
else if (RB_TYPE_P(y, T_FLOAT)) {
b = RFLOAT_VALUE(y);
#if defined(_MSC_VER) && _MSC_VER < 1300
if (isnan(b)) return Qfalse;
#endif
}
else {
return rb_num_coerce_relop(x, y, '>');
}
#if defined(_MSC_VER) && _MSC_VER < 1300
if (isnan(a)) return Qfalse;
#endif
return (a > b)?Qtrue:Qfalse;
}
float >= real → true or false
إعادة true
إذا كان float
أكبر من أو يساوي real
.
نتيجة NaN >= NaN غير معرفة، لذا تُعاد قيمة تعتمد على التنفيذ.
static VALUE
flo_ge(VALUE x, VALUE y)
{
double a, b;
a = RFLOAT_VALUE(x);
if (RB_TYPE_P(y, T_FIXNUM) || RB_TYPE_P(y, T_BIGNUM)) {
VALUE rel = rb_integer_float_cmp(y, x);
if (FIXNUM_P(rel))
return -FIX2INT(rel) >= 0 ? Qtrue : Qfalse;
return Qfalse;
}
else if (RB_TYPE_P(y, T_FLOAT)) {
b = RFLOAT_VALUE(y);
#if defined(_MSC_VER) && _MSC_VER < 1300
if (isnan(b)) return Qfalse;
#endif
}
else {
return rb_num_coerce_relop(x, y, idGE);
}
#if defined(_MSC_VER) && _MSC_VER < 1300
if (isnan(a)) return Qfalse;
#endif
return (a >= b)?Qtrue:Qfalse;
}
abs → float
إعادة القيمة المطلقة للتابع float
.
(-34.56).abs #=> 34.56
-34.56.abs #=> 34.56
34.56.abs #=> 34.56
#magnitude
اسم مستعار للتابع #abs
.
VALUE
rb_float_abs(VALUE flt)
{
double val = fabs(RFLOAT_VALUE(flt));
return DBL2NUM(val);
}
angle → 0 or float
إعادة 0 إذا كانت القيمة موجبة، أو "ط (pi)" خلاف ذلك.
static VALUE
float_arg(VALUE self)
{
if (isnan(RFLOAT_VALUE(self)))
return self;
if (f_tpositive_p(self))
return INT2FIX(0);
return rb_const_get(rb_mMath, id_PI);
}
arg → 0 or float
إعادة 0 إذا كانت القيمة موجبة، أو "ط (pi)" خلاف ذلك.
static VALUE
float_arg(VALUE self)
{
if (isnan(RFLOAT_VALUE(self)))
return self;
if (f_tpositive_p(self))
return INT2FIX(0);
return rb_const_get(rb_mMath, id_PI);
}
ceil([ndigits]) → integer or float
إعادة أصغر رقم أكبر من أو يساوي float
مع دقة ndigits
رقم (القيمة الافتراضية: 0).
عندما تكون الدقة سالبة، تكون القيمة المُعادة عدد صحيح متبوعًا بعدد أصفار مقداره ndigits.abs
على الأقل.
إعادة عدد عشري عندما يكون ndigits
موجبًا، وإلا يُعاد عددٌ صحيحٌ.
1.2.ceil #=> 2
2.0.ceil #=> 2
(-1.2).ceil #=> -1
(-2.0).ceil #=> -2
1.234567.ceil(2) #=> 1.24
1.234567.ceil(3) #=> 1.235
1.234567.ceil(4) #=> 1.2346
1.234567.ceil(5) #=> 1.23457
34567.89.ceil(-5) #=> 100000
34567.89.ceil(-4) #=> 40000
34567.89.ceil(-3) #=> 35000
34567.89.ceil(-2) #=> 34600
34567.89.ceil(-1) #=> 34570
34567.89.ceil(0) #=> 34568
34567.89.ceil(1) #=> 34567.9
34567.89.ceil(2) #=> 34567.89
34567.89.ceil(3) #=> 34567.89
يُلاحظ أن الدقة المحدودة للنقطة العائمة الحسابية قد تؤدي إلى نتائج مُدهشة:
(2.1 / 0.7).ceil #=> 4 (!)
coerce(numeric) → array
إعادة مصفوفة يتمثَّل فيها كلٌ من numeric
و float
ككائنات Float.
ويتحقق ذلك عن طريق تحويل numeric إلى Float.
1.2.coerce(3) #=> [3.0, 1.2]
2.5.coerce(1.1) #=> [1.1, 2.5]
denominator → integer
إعادة المقام (موجب دائمًا). والنتيجة تعتمد على الآلة.
انظر أيضا #numerator
.
static VALUE
float_denominator(VALUE self)
{
double d = RFLOAT_VALUE(self);
VALUE r;
if (isinf(d) || isnan(d))
return INT2FIX(1);
r = float_to_r(self);
if (canonicalization && k_integer_p(r)) {
return ONE;
}
return nurat_denominator(r);
}
divmod(numeric) → array
راجع Numeric#divmod
.
42.0.divmod(6) #=> [7, 0.0]
42.0.divmod(5) #=> [8, 2.0]
eql?(obj) → true or false
إعادة true
فقط إذا كانت obj
من النوع Float وله نفس قيمة float
. علي النقيض من ذلك مع Float#==
، الذي يُجري تحويلات على النوع.
1.0.eql?(1) #=> false
نتيجة NaN.eql?(NaN) غير معرفة، لذا تُعاد قيمة تعتمد على التنفيذ.
VALUE
rb_float_eql(VALUE x, VALUE y)
{
if (RB_TYPE_P(y, T_FLOAT)) {
double a = RFLOAT_VALUE(x);
double b = RFLOAT_VALUE(y);
#if defined(_MSC_VER) && _MSC_VER < 1300
if (isnan(a) || isnan(b)) return Qfalse;
#endif
if (a == b)
return Qtrue;
}
return Qfalse;
}
fdiv(numeric) → float
إعادة float / numeric
، مثل Float#/
.
static VALUE
flo_quo(VALUE x, VALUE y)
{
return num_funcall1(x, '/', y);
}
finite? → true or false
إعادة true
إذا كان float
عدد نقطة عائمة IEEE صالح، أي أنه ليس لا نهائي و #nan?
قيمتها false
.
VALUE
rb_flo_is_finite_p(VALUE num)
{
double value = RFLOAT_VALUE(num);
#ifdef HAVE_ISFINITE
if (!isfinite(value))
return Qfalse;
#else
if (isinf(value) || isnan(value))
return Qfalse;
#endif
return Qtrue;
}
floor([ndigits]) → integer or float
إعادة أكبر رقم أصغر من أو يساوي float
مع دقة ndigits
رقم عشري (القيمة الافتراضية: 0).
عندما تكون الدقة سالبة، تكون القيمة المُعادة عدد صحيح متبوعًا بعدد أصفار مقداره ndigits.abs
على الأقل.
إعادة عدد عشري عندما يكون ndigits
موجبًا، وإلا يُعاد عددٌ صحيحٌ.
1.2.floor #=> 1
2.0.floor #=> 2
(-1.2).floor #=> -2
(-2.0).floor #=> -2
1.234567.floor(2) #=> 1.23
1.234567.floor(3) #=> 1.234
1.234567.floor(4) #=> 1.2345
1.234567.floor(5) #=> 1.23456
34567.89.floor(-5) #=> 0
34567.89.floor(-4) #=> 30000
34567.89.floor(-3) #=> 34000
34567.89.floor(-2) #=> 34500
34567.89.floor(-1) #=> 34560
34567.89.floor(0) #=> 34567
34567.89.floor(1) #=> 34567.8
34567.89.floor(2) #=> 34567.89
34567.89.floor(3) #=> 34567.89
يُلاحظ أن الدقة المحدودة للنقطة العائمة الحسابية قد تؤدي إلى نتائج مُدهشة:
(0.3 / 0.1).floor #=> 2 (!)
hash → integer
إعادة رمز التجزئة لهذا الرقم العشري.
راجع أيضًا Object#hash
.
static VALUE
flo_hash(VALUE num)
{
return rb_dbl_hash(RFLOAT_VALUE(num));
}
infinite? → -1, 1, or nil
إعادة nil
أو -1، أو 1 اعتمادًا علي ما إذا كانت القيمة محدودة، أو -Infinity
، أو +Infinity
.
(0.0).infinite? #=> nil
(-1.0/0.0).infinite? #=> -1
(+1.0/0.0).infinite? #=> 1
inspect()
اسم المستعار للتابع to_s
magnitude → float
إعادة القيمة المطلقة للتابع float
.
(-34.56).abs #=> 34.56
-34.56.abs #=> 34.56
34.56.abs #=> 34.56
#magnitude
اسم مستعار للتابع #abs
.
VALUE
rb_float_abs(VALUE flt)
{
double val = fabs(RFLOAT_VALUE(flt));
return DBL2NUM(val);
}
modulo(other) → float
إعادة الوحدة بعد قسمة float
على other
.
6543.21.modulo(137) #=> 104.21000000000004
6543.21.modulo(137.24) #=> 92.92999999999961
static VALUE
flo_mod(VALUE x, VALUE y)
{
double fy;
if (RB_TYPE_P(y, T_FIXNUM)) {
fy = (double)FIX2LONG(y);
}
else if (RB_TYPE_P(y, T_BIGNUM)) {
fy = rb_big2dbl(y);
}
else if (RB_TYPE_P(y, T_FLOAT)) {
fy = RFLOAT_VALUE(y);
}
else {
return rb_num_coerce_bin(x, y, '%');
}
return DBL2NUM(ruby_float_mod(RFLOAT_VALUE(x), fy));
}
nan? → true or false
إعادة true
إذا كان float
عدد نقطة عائمة IEEE غير صالح.
a = -1.0 #=> -1.0
a.nan? #=> false
a = 0.0/0.0 #=> NaN
a.nan? #=> true
static VALUE
flo_is_nan_p(VALUE num)
{
double value = RFLOAT_VALUE(num);
return isnan(value) ? Qtrue : Qfalse;
}
negative? → true or false
إعادة true
إذا كان float
أقل من 0.
static VALUE
flo_negative_p(VALUE num)
{
double f = RFLOAT_VALUE(num);
return f < 0.0 ? Qtrue : Qfalse;
}
next_float → float
إعادة عدد النقطة العائمة القابل للتمثيل التالي.
Float::MAX.next_float
و Float::INFINITY.next_float
هما Float::INFINITY
.
Float::NAN.next_float
هو Float::NAN
.
فعلى سبيل المثال:
0.01.next_float #=> 0.010000000000000002
1.0.next_float #=> 1.0000000000000002
100.0.next_float #=> 100.00000000000001
0.01.next_float - 0.01 #=> 1.734723475976807e-18
1.0.next_float - 1.0 #=> 2.220446049250313e-16
100.0.next_float - 100.0 #=> 1.4210854715202004e-14
f = 0.01; 20.times { printf "%-20a %s\n", f, f.to_s; f = f.next_float }
#=> 0x1.47ae147ae147bp-7 0.01
# 0x1.47ae147ae147cp-7 0.010000000000000002
# 0x1.47ae147ae147dp-7 0.010000000000000004
# 0x1.47ae147ae147ep-7 0.010000000000000005
# 0x1.47ae147ae147fp-7 0.010000000000000007
# 0x1.47ae147ae148p-7 0.010000000000000009
# 0x1.47ae147ae1481p-7 0.01000000000000001
# 0x1.47ae147ae1482p-7 0.010000000000000012
# 0x1.47ae147ae1483p-7 0.010000000000000014
# 0x1.47ae147ae1484p-7 0.010000000000000016
# 0x1.47ae147ae1485p-7 0.010000000000000018
# 0x1.47ae147ae1486p-7 0.01000000000000002
# 0x1.47ae147ae1487p-7 0.010000000000000021
# 0x1.47ae147ae1488p-7 0.010000000000000023
# 0x1.47ae147ae1489p-7 0.010000000000000024
# 0x1.47ae147ae148ap-7 0.010000000000000026
# 0x1.47ae147ae148bp-7 0.010000000000000028
# 0x1.47ae147ae148cp-7 0.01000000000000003
# 0x1.47ae147ae148dp-7 0.010000000000000031
# 0x1.47ae147ae148ep-7 0.010000000000000033
f = 0.0
100.times { f += 0.1 }
f #=> 9.99999999999998 # should be 10.0 in the ideal world.
10-f #=> 1.9539925233402755e-14 # the floating point error.
10.0.next_float-10 #=> 1.7763568394002505e-15 # 1 ulp (unit in the last place).
(10-f)/(10.0.next_float-10) #=> 11.0 # the error is 11 ulp.
(10-f)/(10*Float::EPSILON) #=> 8.8 # approximation of the above.
"%a" % 10 #=> "0x1.4p+3"
"%a" % f #=> "0x1.3fffffffffff5p+3" # the last hex digit is 5. 16 - 5 = 11 ulp.
numerator → integer
إعادة البسط. والنتيجة تعتمد على الآلة.
n = 0.3.numerator #=> 5404319552844595
d = 0.3.denominator #=> 18014398509481984
n.fdiv(d) #=> 0.3
انظر أيضا #denominator
.
static VALUE
float_numerator(VALUE self)
{
double d = RFLOAT_VALUE(self);
VALUE r;
if (isinf(d) || isnan(d))
return self;
r = float_to_r(self);
if (canonicalization && k_integer_p(r)) {
return r;
}
return nurat_numerator(r);
}
phase → 0 or float
إعادة 0 إذا كانت القيمة موجبة، أو "ط (pi)" خلاف ذلك.
static VALUE
float_arg(VALUE self)
{
if (isnan(RFLOAT_VALUE(self)))
return self;
if (f_tpositive_p(self))
return INT2FIX(0);
return rb_const_get(rb_mMath, id_PI);
}
positive? → true or false
إعادة true
إذا كان float
أكبر من 0.
static VALUE
flo_positive_p(VALUE num)
{
double f = RFLOAT_VALUE(num);
return f > 0.0 ? Qtrue : Qfalse;
}
prev_float → float
إعادة عدد النقطة العائمة القابل للتمثيل السابق.
(-Float::MAX).prev_float
و (-Float::INFINITY).prev_float
هما -Float::INFINITY
.
Float::NAN.prev_float
هو Float::NAN
.
فعلى سبيل المثال:
0.01.prev_float #=> 0.009999999999999998
1.0.prev_float #=> 0.9999999999999999
100.0.prev_float #=> 99.99999999999999
0.01 - 0.01.prev_float #=> 1.734723475976807e-18
1.0 - 1.0.prev_float #=> 1.1102230246251565e-16
100.0 - 100.0.prev_float #=> 1.4210854715202004e-14
f = 0.01; 20.times { printf "%-20a %s\n", f, f.to_s; f = f.prev_float }
#=> 0x1.47ae147ae147bp-7 0.01
# 0x1.47ae147ae147ap-7 0.009999999999999998
# 0x1.47ae147ae1479p-7 0.009999999999999997
# 0x1.47ae147ae1478p-7 0.009999999999999995
# 0x1.47ae147ae1477p-7 0.009999999999999993
# 0x1.47ae147ae1476p-7 0.009999999999999992
# 0x1.47ae147ae1475p-7 0.00999999999999999
# 0x1.47ae147ae1474p-7 0.009999999999999988
# 0x1.47ae147ae1473p-7 0.009999999999999986
# 0x1.47ae147ae1472p-7 0.009999999999999985
# 0x1.47ae147ae1471p-7 0.009999999999999983
# 0x1.47ae147ae147p-7 0.009999999999999981
# 0x1.47ae147ae146fp-7 0.00999999999999998
# 0x1.47ae147ae146ep-7 0.009999999999999978
# 0x1.47ae147ae146dp-7 0.009999999999999976
# 0x1.47ae147ae146cp-7 0.009999999999999974
# 0x1.47ae147ae146bp-7 0.009999999999999972
# 0x1.47ae147ae146ap-7 0.00999999999999997
# 0x1.47ae147ae1469p-7 0.009999999999999969
# 0x1.47ae147ae1468p-7 0.009999999999999967
quo(numeric) → float
إعادة float / numeric
، مثل Float#/
.
static VALUE
flo_quo(VALUE x, VALUE y)
{
return num_funcall1(x, '/', y);
}
rationalize([eps]) → rational
إعادة تقريب ابسط للقيمة (flt-|eps| <= result <= flt+|eps|)
. إذا لم يتاح الوسيط الاختياري eps
، سيُختار تلقائيًا.
0.3.rationalize #=> (3/10)
1.333.rationalize #=> (1333/1000)
1.333.rationalize(0.01) #=> (4/3)
انظر أيضا #to_r
.
static VALUE
float_rationalize(int argc, VALUE *argv, VALUE self)
{
VALUE e;
double d = RFLOAT_VALUE(self);
if (d < 0.0)
return rb_rational_uminus(float_rationalize(argc, argv, DBL2NUM(-d)));
rb_scan_args(argc, argv, "01", &e);
if (argc != 0) {
return rb_flt_rationalize_with_prec(self, e);
}
else {
return rb_flt_rationalize(self);
}
}
round([ndigits] [, half: mode]) → integer or float
إعادة float
مُقرَّب إلى أقرب قيمة بدقة أرقام عشرية مقدارها ndigits
(القيمة الافتراضية: 0).
عندما تكون الدقة سالبة، تكون القيمة المُعادة عدد صحيح متبوعًا بعدد أصفار مقداره ndigits.abs
على الأقل.
إعادة عدد عشري عندما يكون ndigits
موجبًا، وإلا يُعاد عددٌا صحيحٌا.
1.4.round #=> 1
1.5.round #=> 2
1.6.round #=> 2
(-1.5).round #=> -2
1.234567.round(2) #=> 1.23
1.234567.round(3) #=> 1.235
1.234567.round(4) #=> 1.2346
1.234567.round(5) #=> 1.23457
34567.89.round(-5) #=> 0
34567.89.round(-4) #=> 30000
34567.89.round(-3) #=> 35000
34567.89.round(-2) #=> 34600
34567.89.round(-1) #=> 34570
34567.89.round(0) #=> 34568
34567.89.round(1) #=> 34567.9
34567.89.round(2) #=> 34567.89
34567.89.round(3) #=> 34567.89
إذا أُتيح وسيط الكلمة المفتاحية half الاختياري، ستُقرَّب الأرقام التي تقع في المنتصف بين قيمتين مقرَّبتين ممكنتين وفقًا للوضع mode المُحدَّد الكاسر للعلاقة:
- :up أو nil: تقريب النصف بعيدًا عن الصفر (الوضع الافتراضي).
- :down: تقريب النصف باتجاه الصفر.
- :even: تقريب النصف باتجاه أقرب عدد زوجي.
2.5.round(half: :up) #=> 3
2.5.round(half: :down) #=> 2
2.5.round(half: :even) #=> 2
3.5.round(half: :up) #=> 4
3.5.round(half: :down) #=> 3
3.5.round(half: :even) #=> 4
(-2.5).round(half: :up) #=> -3
(-2.5).round(half: :down) #=> -2
(-2.5).round(half: :even) #=> -2
to_f → self
بما أن float
هو بالأصل Float، يُعيد self
.
static VALUE
flo_to_f(VALUE num)
{
return num;
}
to_i → integer
إعادة float
مبتورًا إلى Integer
.
1.2.to_i #=> 1
(-1.2).to_i #=> -1
يُلاحظ أن الدقة المحدودة للنقطة العائمة الحسابية قد تؤدي إلى نتائج مُدهشة:
(0.3 / 0.1).to_i #=> 2 (!)
to_int
هو اسم مستعار للتابع to_i
.
static VALUE
flo_to_i(VALUE num)
{
double f = RFLOAT_VALUE(num);
if (f > 0.0) f = floor(f);
if (f < 0.0) f = ceil(f);
return dbl2ival(f);
}
to_int → integer
إعادة float
مبتورًا إلى Integer
.
1.2.to_i #=> 1
(-1.2).to_i #=> -1
يُلاحظ أن الدقة المحدودة للنقطة العائمة الحسابية قد تؤدي إلى نتائج مُدهشة:
(0.3 / 0.1).to_i #=> 2 (!)
to_int
هو اسم مستعار للتابع to_i
.
static VALUE
flo_to_i(VALUE num)
{
double f = RFLOAT_VALUE(num);
if (f > 0.0) f = floor(f);
if (f < 0.0) f = ceil(f);
return dbl2ival(f);
}
to_r → rational
إعادة قيمة نسبية.
2.0.to_r #=> (2/1)
2.5.to_r #=> (5/2)
-0.75.to_r #=> (-3/4)
0.0.to_r #=> (0/1)
0.3.to_r #=> (5404319552844595/18014398509481984)
ملاحظة: 0.3.to_r
ليس هي نفسه “0.3”.to_r
. وهذا الأخير يعادل "3/10".to_r
، ولكن الأول ليس كذلك.
0.3.to_r == 3/10r #=> false
"0.3".to_r == 3/10r #=> true
انظر أيضا #rationalize
.
static VALUE
float_to_r(VALUE self)
{
VALUE f, n;
float_decode_internal(self, &f, &n);
#if FLT_RADIX == 2
{
long ln = FIX2LONG(n);
if (ln == 0)
return rb_rational_new1(f);
if (ln > 0)
return rb_rational_new1(rb_int_lshift(f, n));
ln = -ln;
return rb_rational_new2(f, rb_int_lshift(ONE, INT2FIX(ln)));
}
#else
f = rb_int_mul(f, rb_int_pow(INT2FIX(FLT_RADIX), n));
if (RB_TYPE_P(f, T_RATIONAL))
return f;
return rb_rational_new1(f);
#endif
}
to_s → string
إعادة سلسلة تحتوي على تمثيل self
. كما هو حال الشكل الثابت أو الأسي للتابع float
، قد يُعيد الاستدعاء NaN
و Infinity
و -Infinity
.
static VALUE
flo_to_s(VALUE flt)
{
enum {decimal_mant = DBL_MANT_DIG-DBL_DIG};
enum {float_dig = DBL_DIG+1};
char buf[float_dig + (decimal_mant + CHAR_BIT - 1) / CHAR_BIT + 10];
double value = RFLOAT_VALUE(flt);
VALUE s;
char *p, *e;
int sign, decpt, digs;
if (isinf(value)) {
static const char minf[] = "-Infinity";
const int pos = (value > 0); /* skip "-" */
return rb_usascii_str_new(minf+pos, strlen(minf)-pos);
}
else if (isnan(value))
return rb_usascii_str_new2("NaN");
p = ruby_dtoa(value, 0, 0, &decpt, &sign, &e);
s = sign ? rb_usascii_str_new_cstr("-") : rb_usascii_str_new(0, 0);
if ((digs = (int)(e - p)) >= (int)sizeof(buf)) digs = (int)sizeof(buf) - 1;
memcpy(buf, p, digs);
xfree(p);
if (decpt > 0) {
if (decpt < digs) {
memmove(buf + decpt + 1, buf + decpt, digs - decpt);
buf[decpt] = '.';
rb_str_cat(s, buf, digs + 1);
}
else if (decpt <= DBL_DIG) {
long len;
char *ptr;
rb_str_cat(s, buf, digs);
rb_str_resize(s, (len = RSTRING_LEN(s)) + decpt - digs + 2);
ptr = RSTRING_PTR(s) + len;
if (decpt > digs) {
memset(ptr, '0', decpt - digs);
ptr += decpt - digs;
}
memcpy(ptr, ".0", 2);
}
else {
goto exp;
}
}
else if (decpt > -4) {
long len;
char *ptr;
rb_str_cat(s, "0.", 2);
rb_str_resize(s, (len = RSTRING_LEN(s)) - decpt + digs);
ptr = RSTRING_PTR(s);
memset(ptr += len, '0', -decpt);
memcpy(ptr -= decpt, buf, digs);
}
else {
exp:
if (digs > 1) {
memmove(buf + 2, buf + 1, digs - 1);
}
else {
buf[2] = '0';
digs++;
}
buf[1] = '.';
rb_str_cat(s, buf, digs + 1);
rb_str_catf(s, "e%+03d", decpt - 1);
}
return s;
}
ويُعيَّن له أيضًا الاسم المستعار: inspect
.
truncate([ndigits]) → integer or float
إعادة float
مبتورًا (نحو الصفر) إلى دقة أرقام عشرية ndigits
(القيمة الافتراضية: 0).
عندما تكون الدقة سالبة، تكون القيمة المُعادة عدد صحيح متبوعًا بعدد أصفار مقداره ndigits.abs
على الأقل.
إعادة عدد عشري عندما يكون ndigits
موجبًا، وإلا يُعاد عددٌ صحيحٌ.
2.8.truncate #=> 2
(-2.8).truncate #=> -2
1.234567.truncate(2) #=> 1.23
34567.89.truncate(-2) #=> 34500
يُلاحظ أن الدقة المحدودة للنقطة العائمة الحسابية قد تؤدي إلى نتائج مُدهشة:
(0.3 / 0.1).truncate #=> 2 (!)
zero? → true or false
إعادة true
إذا كان float
يساوي 0.
static VALUE
flo_zero_p(VALUE num)
{
if (RFLOAT_VALUE(num) == 0.0) {
return Qtrue;
}
return Qfalse;
}