summaryrefslogtreecommitdiff
path: root/internal.h
diff options
context:
space:
mode:
Diffstat (limited to 'internal.h')
-rw-r--r--internal.h64
1 files changed, 64 insertions, 0 deletions
diff --git a/internal.h b/internal.h
index 424f6f5d8f..7c5a42a521 100644
--- a/internal.h
+++ b/internal.h
@@ -478,6 +478,70 @@ int rb_num_negative_p(VALUE);
VALUE rb_int_succ(VALUE num);
VALUE rb_int_pred(VALUE num);
+#if USE_FLONUM
+#define RUBY_BIT_ROTL(v, n) (((v) << (n)) | ((v) >> ((sizeof(v) * 8) - n)))
+#define RUBY_BIT_ROTR(v, n) (((v) >> (n)) | ((v) << ((sizeof(v) * 8) - n)))
+#endif
+
+static inline double
+rb_float_value_inline(VALUE v)
+{
+#if USE_FLONUM
+ if (FLONUM_P(v)) {
+ if (v != (VALUE)0x8000000000000002) { /* LIKELY */
+ union {
+ double d;
+ VALUE v;
+ } t;
+
+ VALUE b63 = (v >> 63);
+ /* e: xx1... -> 011... */
+ /* xx0... -> 100... */
+ /* ^b63 */
+ t.v = RUBY_BIT_ROTR((2 - b63) | (v & ~0x03), 3);
+ return t.d;
+ }
+ else {
+ return 0.0;
+ }
+ }
+#endif
+ return ((struct RFloat *)v)->float_value;
+}
+
+static inline VALUE
+rb_float_new_inline(double d)
+{
+#if USE_FLONUM
+ union {
+ double d;
+ VALUE v;
+ } t;
+ int bits;
+
+ t.d = d;
+ bits = (int)((VALUE)(t.v >> 60) & 0x7);
+ /* bits contains 3 bits of b62..b60. */
+ /* bits - 3 = */
+ /* b011 -> b000 */
+ /* b100 -> b001 */
+
+ if (t.v != 0x3000000000000000 /* 1.72723e-77 */ &&
+ !((bits-3) & ~0x01)) {
+ return (RUBY_BIT_ROTL(t.v, 3) & ~(VALUE)0x01) | 0x02;
+ }
+ else if (t.v == (VALUE)0) {
+ /* +0.0 */
+ return 0x8000000000000002;
+ }
+ /* out of range */
+#endif
+ return rb_float_new_in_heap(d);
+}
+
+#define rb_float_value(v) rb_float_value_inline(v)
+#define rb_float_new(d) rb_float_new_inline(d)
+
/* object.c */
VALUE rb_obj_equal(VALUE obj1, VALUE obj2);