GitHub

@@ -182,8 +182,51 @@ mrb_obj_id(mrb_value obj)

182182

* RFloat object on the heap.

183183

* - If `MRB_64BIT` and `MRB_USE_FLOAT32` are defined, it stores the float

184184

* in the lower bits of the word, shifted and tagged.

185-

* - Otherwise, it stores the float directly in the word, tagged.

185+

* - Otherwise (64-bit float64), it uses rotation encoding to store the

186+

* float losslessly inline. Floats outside the inline exponent range

187+

* [-255, +256] are heap-allocated as RFloat.

186188

*/

189+190+

#if !defined(MRB_WORDBOX_NO_FLOAT_TRUNCATE) && !defined(MRB_USE_FLOAT32)

191+

/*

192+

* Rotation-based float encoding for 64-bit + float64.

193+

*

194+

* Encode: rotl64(float64_bits - ADDEND, 3) produces a tagged value

195+

* with bottom 2 bits == 10 (WORDBOX_FLOAT_FLAG).

196+

* Decode: rotl64(tagged_value, 61) + ADDEND recovers the original bits.

197+

*

198+

* The addend shifts the exponent so that biased exponents [768, 1279]

199+

* (actual [-255, +256]) produce the correct tag pattern after rotation.

200+

* This covers all practical float values with full precision.

201+

*/

202+

#define WORDBOX_FLOAT_ROTATE 3

203+

#define WORDBOX_FLOAT_EXP_MIN (1023 - 255) /* 768 */

204+

#define WORDBOX_FLOAT_EXP_MAX (1023 + 256) /* 1279 */

205+

#define WORDBOX_FLOAT_ADDEND ((uint64_t)((int64_t)(WORDBOX_FLOAT_EXP_MIN - (WORDBOX_FLOAT_FLAG << 9)) << 52))

206+207+

static uint64_t

208+

wordbox_rotl64(uint64_t a, int n)

209+

{

210+

return (a << n) | (a >> (64 - n));

211+

}

212+213+

static uint64_t

214+

wordbox_float64_to_u64(double d)

215+

{

216+

union { double d; uint64_t u; } u;

217+

u.d = d;

218+

return u.u;

219+

}

220+221+

static double

222+

wordbox_u64_to_float64(uint64_t v)

223+

{

224+

union { double d; uint64_t u; } u;

225+

u.u = v;

226+

return u.d;

227+

}

228+

#endif

229+187230

MRB_API mrb_value

188231

mrb_word_boxing_float_value(mrb_state *mrb, mrb_float f)

189232

{

@@ -197,7 +240,21 @@ mrb_word_boxing_float_value(mrb_state *mrb, mrb_float f)

197240

v.w = 0;

198241

v.f = f;

199242

v.w = (v.w<<2) | 2;

243+

#elif defined(MRB_64BIT)

244+

{

245+

uint64_t bits = wordbox_float64_to_u64((double)f);

246+

uint64_t exp = (bits >> 52) & 0x7FF;

247+

if (exp >= WORDBOX_FLOAT_EXP_MIN && exp <= WORDBOX_FLOAT_EXP_MAX) {

248+

v.w = (uintptr_t)wordbox_rotl64(bits - WORDBOX_FLOAT_ADDEND, WORDBOX_FLOAT_ROTATE);

249+

}

250+

else {

251+

v.p = mrb_obj_alloc(mrb, MRB_TT_FLOAT, mrb->float_class);

252+

v.fp->f = f;

253+

v.bp->frozen = 1;

254+

}

255+

}

200256

#else

257+

/* 32-bit + float32: truncate bottom 2 bits */

201258

v.f = f;

202259

v.w = (v.w & ~3) | 2;

203260

#endif

@@ -207,26 +264,36 @@ mrb_word_boxing_float_value(mrb_state *mrb, mrb_float f)

207264208265

#ifndef MRB_WORDBOX_NO_FLOAT_TRUNCATE

209266

/*

210-

* Unboxes an `mrb_value` to an `mrb_float` when word boxing is used and

211-

* float truncation (`MRB_WORDBOX_NO_FLOAT_TRUNCATE`) is not disabled.

212-

* The function extracts the float value from the `mrb_value`'s union

213-

* representation (`u.value`).

214-

* - If `MRB_64BIT` and `MRB_USE_FLOAT32` are defined, the word (`u.w`)

215-

* is right-shifted by 2 bits to retrieve the float.

216-

* - Otherwise, the lower 2 bits of the word (`u.w`) are cleared to

217-

* retrieve the float.

267+

* Unboxes an `mrb_value` to an `mrb_float`.

268+

* - If `MRB_USE_FLOAT32`: right-shift by 2 to retrieve the float.

269+

* - Otherwise (rotation encoding): decode inline floats via rotation,

270+

* or read from heap RFloat for edge cases.

218271

*/

219272

MRB_API mrb_float

220273

mrb_word_boxing_value_float(mrb_value v)

221274

{

275+

#if defined(MRB_64BIT) && defined(MRB_USE_FLOAT32)

222276

union mrb_value_ u;

223277

u.value = v;

224-

#if defined(MRB_64BIT) && defined(MRB_USE_FLOAT32)

225278

u.w >>= 2;

279+

return u.f;

280+

#elif defined(MRB_64BIT)

281+

if ((v.w & WORDBOX_FLOAT_MASK) == WORDBOX_FLOAT_FLAG) {

282+

return (mrb_float)wordbox_u64_to_float64(

283+

wordbox_rotl64((uint64_t)v.w, 64 - WORDBOX_FLOAT_ROTATE) + WORDBOX_FLOAT_ADDEND);

284+

}

285+

else {

286+

union mrb_value_ u;

287+

u.value = v;

288+

return u.fp->f;

289+

}

226290

#else

291+

/* 32-bit + float32: clear tag bits */

292+

union mrb_value_ u;

293+

u.value = v;

227294

u.w &= ~3;

228-

#endif

229295

return u.f;

296+

#endif

230297

}

231298

#endif

232299

#endif /* MRB_NO_FLOAT */

Read the original on github.com ↗