1 // -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the GNU General Public License v3+, or later.
7 // See license.mkd for licensing and copyright information.
8 // ---------------------------------------------------------------------------
10 package cc
.squirreljme
.jvm
;
12 import cc
.squirreljme
.jvm
.mle
.MathShelf
;
13 import cc
.squirreljme
.runtime
.cldc
.annotation
.SquirrelJMEVendorApi
;
14 import cc
.squirreljme
.runtime
.cldc
.debug
.Debugging
;
15 import cc
.squirreljme
.runtime
.cldc
.util
.UnsignedInteger
;
18 * Software math operations on 32-bit floats.
20 * This source file uses parts of the Berkeley SoftFloat Release 3e library,
21 * converted into Java. See the 3rd party licenses documentation.
26 @SuppressWarnings({"CommentedOutCode", "MagicNumber", "OverlyComplexClass"})
27 public final class SoftFloat
31 public static final int SIGN_MASK
=
32 0b1000_0000_0000_0000__0000_0000_0000_0000
;
34 /** The zero check mask. */
36 public static final int ZERO_CHECK_MASK
=
41 public static final int EXPONENT_MASK
=
42 0b0111_1111_1000_0000__0000_0000_0000_0000
;
46 public static final int FRACTION_MASK
=
47 0b0000_0000_0111_1111__1111_1111_1111_1111
;
49 /** The mask for NaN values. */
51 public static final int NAN_MASK
=
52 0b0111_1111_1000_0000__0000_0000_0000_0000
;
54 /** Exponent shift. */
55 private static final byte _EXP_SHIFT
=
58 /** Default NaN value. */
59 public static final float FLOAT_DEFAULT_NAN
=
60 Float
.intBitsToFloat(0xFFC0_
0000);
62 /** Integer from negative overflow. */
63 private static final int _INT_FROM_NEGOVER
=
66 /** Integer from positive overflow. */
67 private static final int _INT_FROM_POSOVER
=
70 /** Round near even mode. */
71 private static final int _ROUND_NEAR_EVEN
=
92 public static float add(int __a
, int __b
)
94 throw Debugging
.todo();
98 * Compares two values, NaN returns {@code -1}.
102 * @return The result.
105 @SquirrelJMEVendorApi
106 @SuppressWarnings("SpellCheckingInspection")
107 public static int cmpl(int __a
, int __b
)
109 if (SoftFloat
.isNaN(__a
) || SoftFloat
.isNaN(__b
))
112 return SoftFloat
.__cmp(__a
, __b
);
116 * Compares two values, NaN returns {@code 1}.
120 * @return The result.
123 @SquirrelJMEVendorApi
124 @SuppressWarnings("SpellCheckingInspection")
125 public static int cmpg(int __a
, int __b
)
127 if (SoftFloat
.isNaN(__a
) || SoftFloat
.isNaN(__b
))
130 return SoftFloat
.__cmp(__a
, __b
);
134 * Divides two values.
138 * @return The result.
141 @SquirrelJMEVendorApi
142 public static float div(int __a
, int __b
)
144 throw Debugging
.todo();
148 * Is this Not a Number?
150 * @param __a The value to check.
151 * @return If this is not a number.
154 @SquirrelJMEVendorApi
155 public static boolean isNaN(int __a
)
157 return SoftFloat
.NAN_MASK
== (__a
& SoftFloat
.NAN_MASK
);
161 * Multiplies two values.
165 * @return The result.
168 @SquirrelJMEVendorApi
169 public static float mul(int __a
, int __b
)
172 boolean signA
= SoftFloat
.__signF32UI(__a
);
173 int expA
= SoftFloat
.__expF32UI(__a
);
174 int sigA
= SoftFloat
.__fracF32UI(__a
);
177 boolean signB
= SoftFloat
.__signF32UI(__b
);
178 int expB
= SoftFloat
.__expF32UI(__b
);
179 int sigB
= SoftFloat
.__fracF32UI(__b
);
181 // Will this result in a negative value?
182 boolean signZ
= signA ^ signB
;
184 boolean returnInfinite
= false;
188 // if ( sigA || ((expB == 0xFF) && sigB) )
189 if (sigA
!= 0 || ((expB
== 0xFF) && (sigB
!= 0)))
190 return Float
.intBitsToFloat(
191 SoftFloat
.__propagateNaNF32UI(__a
, __b
));
193 magBits
= expB
| sigB
;
194 returnInfinite
= true;
197 if (!returnInfinite
&& expB
== 0xFF)
201 return Float
.intBitsToFloat(
202 SoftFloat
.__propagateNaNF32UI(__a
, __b
));
204 magBits
= expA
| sigA
;
205 returnInfinite
= true;
208 // Returning infinite value?
213 return SoftFloat
.FLOAT_DEFAULT_NAN
;
214 return Float
.intBitsToFloat(
215 SoftFloat
.__packToF32UI(signZ
, 0xFF, 0));
223 return Float
.intBitsToFloat(
224 SoftFloat
.__packToF32UI(signZ
, 0, 0));
226 long normExpSig
= SoftFloat
.__normSubnormalF32Sig(sigA
);
227 expA
= (short)MathShelf
.longUnpackHigh(normExpSig
);
228 sigA
= MathShelf
.longUnpackLow(normExpSig
);
236 return Float
.intBitsToFloat(
237 SoftFloat
.__packToF32UI(signZ
, 0, 0));
239 long normExpSig
= SoftFloat
.__normSubnormalF32Sig(sigB
);
240 expB
= (short)MathShelf
.longUnpackHigh(normExpSig
);
241 sigB
= MathShelf
.longUnpackLow(normExpSig
);
244 int expZ
= (short)(expA
+ expB
- 0x7F);
245 sigA
= (sigA
| 0x0080_
0000) << 7;
246 sigB
= (sigB
| 0x0080_
0000) << 8;
248 // sigZ = softfloat_shortShiftRightJam64(
249 // (uint_fast64_t)sigA * sigB, 32); <-- unsigned multiply
250 int sigZ
= (int)SoftFloat
.__shortShiftRightJam64(
251 (sigA
& 0xFFFF_FFFFL
) * (sigB
& 0xFFFF_FFFFL
), 32);
253 // if ( sigZ < 0x40000000 )
254 if (UnsignedInteger
.compareUnsigned(sigZ
, 0x4000_
0000) < 0)
256 expZ
= (short)(expZ
- 1);
260 return Float
.intBitsToFloat(
261 SoftFloat
.__roundPackToF32(signZ
, expZ
, sigZ
));
268 * @return The result.
271 @SquirrelJMEVendorApi
272 public static float neg(int __a
)
274 throw Debugging
.todo();
278 * Ors a value, used for constant loading.
282 * @return The result.
285 @SquirrelJMEVendorApi
286 public static float or(int __a
, int __b
)
288 return MathShelf
.rawIntToFloat(__a
| __b
);
292 * Remainders a value.
296 * @return The result.
299 @SquirrelJMEVendorApi
300 public static float rem(int __a
, int __b
)
302 throw Debugging
.todo();
310 * @return The result.
313 @SquirrelJMEVendorApi
314 public static float sub(int __a
, int __b
)
316 throw Debugging
.todo();
320 * Converts to double.
323 * @return The result.
326 @SquirrelJMEVendorApi
327 public static double toDouble(int __a
)
329 throw Debugging
.todo();
333 * Converts to integer.
336 * @return The result.
339 @SquirrelJMEVendorApi
340 public static int toInteger(int __a
)
342 boolean sign
= SoftFloat
.__signF32UI(__a
);
343 int exp
= SoftFloat
.__expF32UI(__a
);
344 int sig
= SoftFloat
.__fracF32UI(__a
);
349 // sig64 = (uint_fast64_t) sig<<32;
350 long sig64
= MathShelf
.longPack(0, sig
);
351 int shiftDist
= 0xAA - exp
;
353 if (UnsignedInteger
.compareUnsigned(0, shiftDist
) < 0)
354 sig64
= SoftFloat
.__shiftRightJam64(sig64
, shiftDist
);
356 return SoftFloat
.__roundToI32(sign
, sig64
);
363 * @return The result.
366 @SquirrelJMEVendorApi
367 public static long toLong(int __a
)
369 throw Debugging
.todo();
373 * Compares two values.
377 * @return The result.
380 private static int __cmp(int __a
, int __b
)
382 // Equality, note second means -0 == 0
383 // return (uiA == uiB) || ! (uint32_t) ((uiA | uiB)<<1);
384 if (__a
== __b
|| ((__a
| __b
) << 1) == 0)
388 // (signA != signB) ? signA && ((uint32_t) ((uiA | uiB)<<1) != 0)
389 // : (uiA != uiB) && (signA ^ (uiA < uiB));
390 boolean signA
= (0 != (__a
& SoftFloat
.SIGN_MASK
));
391 boolean signB
= (0 != (__b
& SoftFloat
.SIGN_MASK
));
394 // signA && ((uint32_t) ((uiA | uiB)<<1) != 0)
395 if (signA
&& ((__a
| __b
) << 1) != 0)
399 // (uiA != uiB) && (signA ^ (uiA < uiB))
401 else if (signA ^
(UnsignedInteger
.compareUnsigned(__a
, __b
) < 0))
404 // Anything else assume greater than
409 * Returns the exponent.
411 * @param __a The float to read from.
412 * @return The exponent.
415 private static int __expF32UI(int __a
)
417 // ((int_fast16_t) ((a)>>23) & 0xFF)
418 return (((__a
) >>> SoftFloat
._EXP_SHIFT
) & 0xFF);
422 * Returns the fraction/significand from the floating point value.
424 * @param __a The float to read from.
425 * @return The fraction/significand.
428 private static int __fracF32UI(int __a
)
430 return (__a
& SoftFloat
.FRACTION_MASK
);
434 * Gets if this is a NaN.
436 * @param __a The value to check.
437 * @return If this is a NaN.
440 private static boolean __isNaNF32UI(int __a
)
442 return ((~
(__a
) & 0x7F800000) == 0) &&
443 ((__a
) & 0x007FFFFF) != 0;
447 * Gets if this is a signaling NaN.
449 * @param __a The value to check.
450 * @return If this is a signaling NaN.
453 private static boolean __isSigNaNF32UI(int __a
)
455 return ((__a
& 0x7FC00000) == 0x7F800000) &&
456 (__a
& 0x003FFFFF) != 0;
460 * Normalized round packed to 32-bit float.
462 * @param __sign The sign.
463 * @param __exp The exponent.
464 * @param __sig The significand.
465 * @return The resultant value.
468 protected static int __normRoundPackToF32(boolean __sign
, int __exp
,
473 // shiftDist = softfloat_countLeadingZeros32( __sig ) - 1;
474 shiftDist
= Integer
.numberOfLeadingZeros(__sig
) - 1;
477 // if ( (7 <= shiftDist) && ((unsigned int) exp < 0xFD) ) {
478 if (7 <= shiftDist
&&
479 UnsignedInteger
.compareUnsigned(__exp
, 0xFD) < 0)
481 // uZ.ui = packToF32UI( sign, sig ? exp : 0, sig<<(shiftDist - 7));
482 return SoftFloat
.__packToF32UI(__sign
,
483 (__sig
!= 0 ? __exp
: 0),
484 __sig
<< (shiftDist
- 7));
487 // return softfloat_roundPackToF32( sign, exp, sig<<shiftDist );
488 return SoftFloat
.__roundPackToF32(__sign
, __exp
,
493 * Normalizes a subnormal 32-bit float significand.
495 * @param __sig The significand.
496 * @return The normalized value, the exponent is the high value and
497 * the significand is the low value.
500 private static long __normSubnormalF32Sig(int __sig
)
502 // softfloat_countLeadingZeros32( sig ) - 8;
503 int shiftDist
= Integer
.numberOfLeadingZeros(__sig
) - 8;
505 // struct exp16_sig32 { int_fast16_t exp; uint_fast32_t sig; };
506 // exp = 1 - shiftDist ,, sig = sig<<shiftDist
507 return MathShelf
.longPack(__sig
<< shiftDist
,
508 (short)(1 - shiftDist
));
512 * Packs value to an unsigned integer, note that some of these values are
513 * perfectly fine to overflow into each other such as the significand
514 * being larger than the value.
516 * @param __sign Sign bit.
517 * @param __exp Exponent.
518 * @param __sig Significand.
519 * @return The packed value.
522 protected static int __packToF32UI(boolean __sign
, int __exp
, int __sig
)
524 // (((uint32_t) (sign)<<31) + ((uint32_t) (exp)<<23) + (sig))
525 return (__sign ? SoftFloat
.SIGN_MASK
: 0) + ((__exp
) << 23) + (__sig
);
529 * Propagates the given NaN values.
531 * @param __a The first value.
532 * @param __b The second value.
533 * @return The propagated NaN.
536 private static int __propagateNaNF32UI(int __a
, int __b
)
538 boolean isSigNaNA
= SoftFloat
.__isSigNaNF32UI(__a
);
539 boolean isSigNaNB
= SoftFloat
.__isSigNaNF32UI(__b
);
541 // Make NaNs non-signaling.
542 int uiNonSigA
= __a
| 0x00400000;
543 int uiNonSigB
= __b
| 0x00400000;
545 // Are either of these signaling?
546 if (isSigNaNA
| isSigNaNB
)
551 return SoftFloat
.__isNaNF32UI(__b
) ? uiNonSigB
: uiNonSigA
;
554 return SoftFloat
.__isNaNF32UI(__a
) ? uiNonSigA
: uiNonSigB
;
557 int uiMagA
= __a
& 0x7FFFFFFF;
558 int uiMagB
= __b
& 0x7FFFFFFF;
560 if (UnsignedInteger
.compareUnsigned(uiMagA
, uiMagB
) < 0)
563 if (UnsignedInteger
.compareUnsigned(uiMagB
, uiMagA
) < 0)
566 // return (uiNonSigA < uiNonSigB) ? uiNonSigA : uiNonSigB;
567 if (UnsignedInteger
.compareUnsigned(uiNonSigA
, uiNonSigB
) < 0)
573 * Round and pack to float.
575 * @param __sign The sign.
576 * @param __exp The exponent.
577 * @param __sig The significand.
578 * @return The resultant value.
581 private static int __roundPackToF32(boolean __sign
, int __exp
, int __sig
)
583 int roundIncrement
= 0x40;
584 int roundBits
= __sig
& 0x7F;
586 // if ( 0xFD <= (unsigned int) exp )
587 if (UnsignedInteger
.compareUnsigned(0xFD, __exp
) <= 0)
589 // Negative exponent?
592 __sig
= SoftFloat
.__shiftRightJam32(__sig
, -__exp
);
594 roundBits
= __sig
& 0x7F;
597 // else if ((0xFD < exp) || (0x80000000 <= sig + roundIncrement))
598 else if (0xFD < __exp
||
599 UnsignedInteger
.compareUnsigned(0x8000_
0000,
600 __sig
+ roundIncrement
) <= 0)
602 // uiZ = packToF32UI(__sign, 0xFF, 0) - !roundIncrement;
603 return SoftFloat
.__packToF32UI(__sign
, 0xFF, 0);
607 // sig = (sig + roundIncrement)>>7;
608 __sig
= (__sig
+ roundIncrement
) >>> 7;
610 // sig &= ~(uint_fast32_t) (! (roundBits ^ 0x40) & roundNearEven);
611 __sig
&= ~
(((roundBits ^
0x40) == 0 ?
1 : 0) & 1);
613 // if ( ! sig ) exp = 0;
617 // uiZ = packToF32UI( sign, exp, sig );
618 return SoftFloat
.__packToF32UI(__sign
, __exp
, __sig
);
622 * Rounds to 32-bit integer.
624 * @param __sign The sign.
625 * @param __sig The significand.
626 * @return The resultant integer.
629 private static int __roundToI32(boolean __sign
, long __sig
)
631 int roundBits
= ((int)__sig
) & 0xFFF;
632 int roundIncrement
= 0x800;
633 __sig
+= roundIncrement
;
635 // if ( sig & UINT64_C( 0xFFFFF00000000000 ) ) goto invalid;
636 if ((__sig
& 0xFFFF_F
000_
0000_
0000L) != 0)
637 return __sign ? SoftFloat
._INT_FROM_NEGOVER
:
638 SoftFloat
._INT_FROM_POSOVER
;
641 int sig32
= (int)(__sig
>>> 12);
643 // if (roundBits == 0x800) && (roundMode == softfloat_round_near_even)
644 if (roundBits
== 0x800)
647 int z
= __sign ?
-sig32
: sig32
;
649 // if ( z && ((z < 0) ^ sign) ) goto invalid;
650 if (z
!= 0 && ((z
< 0) ^ __sign
))
651 return __sign ? SoftFloat
._INT_FROM_NEGOVER
:
652 SoftFloat
._INT_FROM_POSOVER
;
658 * Shift right and jam float.
660 * @param __v The value.
661 * @param __uDist The distance.
662 * @return The jammed value.
665 private static int __shiftRightJam32(int __v
, int __uDist
)
667 // uint_fast16_t dist
668 // (dist < 31) ? a>>dist | ((uint32_t) (a<<(-dist & 31)) != 0)
669 if (UnsignedInteger
.compareUnsigned(__uDist
, 31) < 0)
670 return __v
>> __uDist
| (((__v
<< (-__uDist
& 31)) != 0) ?
1 : 0);
673 return (__v
!= 0 ?
1 : 0);
677 * Shift right and jam 64-bit.
679 * @param __a The value.
680 * @param __dist The distance.
681 * @return The result.
684 private static long __shiftRightJam64(long __a
, int __dist
)
686 // (__dist < 63) ? __a>>__dist |
687 // ((uint64_t) (__a<<(-__dist & 63)) != 0) : (__a != 0);
688 if (UnsignedInteger
.compareUnsigned(__dist
, 63) < 0)
689 return __a
>>> __dist
|
690 (((__a
<< (-__dist
& 63)) != 0) ?
1 : 0);
691 return (__a
!= 0 ?
1 : 0);
695 * Short shift right jam at 64-bits.
697 * @param __a The value to jam.
698 * @param __dist The distance.
699 * @return The jammed value.
702 private static long __shortShiftRightJam64(long __a
, int __dist
)
704 // return a>>dist | ((a & (((uint_fast64_t) 1<<dist) - 1)) != 0);
705 return __a
>>> __dist
|
706 (((__a
& ((1L << __dist
) - 1)) != 0) ?
1 : 0);
710 * Returns whether the sign bit is set.
712 * @param __a The float to read from.
713 * @return If the sign bit is set.
716 private static boolean __signF32UI(int __a
)
718 return (__a
& SoftFloat
.SIGN_MASK
) != 0;