JOGL v2.6.0-rc-20250712
JOGL, High-Performance Graphics Binding for Java™ (public API).
Binary16.java
Go to the documentation of this file.
1/**
2 * Copyright 2013 JogAmp Community. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification, are
5 * permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * The views and conclusions contained in the software and documentation are those of the
25 * authors and should not be interpreted as representing official policies, either expressed
26 * or implied, of JogAmp Community.
27 */
28
29package com.jogamp.math;
30
31/**
32 * <p>
33 * Functions to convert values to/from the <code>binary16</code> format
34 * specified in <code>IEEE 754 2008</code>.
35 * </p>
36 */
37
38public final class Binary16
39{
40 /**
41 * The encoded form of negative infinity <code>-∞</code>.
42 */
43
44 public static final char NEGATIVE_INFINITY;
45
46 /**
47 * The encoded form of positive infinity <code>∞</code>.
48 */
49
50 public static final char POSITIVE_INFINITY;
51
52 /**
53 * The encoded form of positive zero <code>0</code>.
54 */
55
56 public static final char POSITIVE_ZERO;
57
58 /**
59 * The encoded form of negative zero <code>-0</code>.
60 */
61
62 public static final char NEGATIVE_ZERO;
63
64 /**
65 * The <i>bias</i> value used to offset the encoded exponent. A given
66 * exponent <code>e</code> is encoded as <code>{@link #BIAS} + e</code>.
67 */
68
69 public static final int BIAS;
70
71 static {
72 NEGATIVE_INFINITY = 0xFC00;
73 POSITIVE_INFINITY = 0x7C00;
74 POSITIVE_ZERO = 0x0000;
75 NEGATIVE_ZERO = 0x8000;
76 BIAS = 15;
77 }
78
79 private static final int MASK_SIGN;
80 private static final int MASK_EXPONENT;
81 private static final int MASK_SIGNIFICAND;
82
83 static {
84 MASK_SIGN = 0x8000;
85 MASK_EXPONENT = 0x7C00;
86 MASK_SIGNIFICAND = 0x03FF;
87 }
88
89 /**
90 * One possible not-a-number value.
91 */
92
93 public static char exampleNaN()
94 {
95 final int n =
98 final char c = (char) n;
99 return c;
100 }
101
102 /**
103 * Return <code>true</code> if the given packed <code>binary16</code> value
104 * is infinite.
105 */
106
107 public static boolean isInfinite(
108 final char k)
109 {
110 if (Binary16.unpackGetExponentUnbiased(k) == 16) {
111 if (Binary16.unpackGetSignificand(k) == 0) {
112 return true;
113 }
114 }
115 return false;
116 }
117
118 /**
119 * Return <code>true</code> if the given packed <code>binary16</code> value
120 * is not a number (<code>NaN</code>).
121 */
122
123 public static boolean isNaN(
124 final char k)
125 {
126 final int e = Binary16.unpackGetExponentUnbiased(k);
127 final int s = Binary16.unpackGetSignificand(k);
128 return (e == 16) && (s > 0);
129 }
130
131 /**
132 * <p>
133 * Convert a double precision floating point value to a packed
134 * <code>binary16</code> value.
135 * </p>
136 * <p>
137 * For the following specific cases, the function returns:
138 * </p>
139 * <ul>
140 * <li><code>NaN</code> iff <code>isNaN(k)</code></li>
141 * <li>{@link #POSITIVE_INFINITY} iff
142 * <code>k == {@link Double#POSITIVE_INFINITY}</code></li>
143 * <li>{@link #NEGATIVE_INFINITY} iff
144 * <code>k == {@link Double#NEGATIVE_INFINITY}</code></li>
145 * <li>{@link #NEGATIVE_ZERO} iff <code>k == -0.0</code></li>
146 * <li>{@link #POSITIVE_ZERO} iff <code>k == 0.0</code></li>
147 * </ul>
148 * <p>
149 * Otherwise, the <code>binary16</code> value that most closely represents
150 * <code>k</code> is returned. This may obviously be an infinite value as
151 * the interval of double precision values is far larger than that of the
152 * <code>binary16</code> type.
153 * </p>
154 *
155 * @see #unpackDouble(char)
156 */
157
158 public static char packDouble(
159 final double k)
160 {
161 if (Double.isNaN(k)) {
162 return Binary16.exampleNaN();
163 }
164 if (k == Double.POSITIVE_INFINITY) {
166 }
167 if (k == Double.NEGATIVE_INFINITY) {
169 }
170 if (Double.doubleToLongBits(k) == Binary64.NEGATIVE_ZERO_BITS) {
171 return Binary16.NEGATIVE_ZERO;
172 }
173 if (k == 0.0) {
174 return Binary16.POSITIVE_ZERO;
175 }
176
177 final long de = Binary64.unpackGetExponentUnbiased(k);
178 final long ds = Binary64.unpackGetSign(k);
179 final long dn = Binary64.unpackGetSignificand(k);
180 final char rsr = Binary16.packSetSignUnchecked((int) ds);
181
182 /**
183 * Extract the 5 least-significant bits of the exponent.
184 */
185
186 final int rem = (int) (de & 0x001F);
187 final char rer = Binary16.packSetExponentUnbiasedUnchecked(rem);
188
189 /**
190 * Extract the 10 most-significant bits of the significand.
191 */
192
193 final long rnm = dn & 0xFFC0000000000L;
194 final long rns = rnm >> 42;
195 final char rnr = Binary16.packSetSignificandUnchecked((int) rns);
196
197 /**
198 * Combine the results.
199 */
200
201 return (char) (rsr | rer | rnr);
202 }
203
204 /**
205 * <p>
206 * Convert a single precision floating point value to a packed
207 * <code>binary16</code> value.
208 * </p>
209 * <p>
210 * For the following specific cases, the function returns:
211 * </p>
212 * <ul>
213 * <li><code>NaN</code> iff <code>isNaN(k)</code></li>
214 * <li>{@link #POSITIVE_INFINITY} iff
215 * <code>k == {@link Float#POSITIVE_INFINITY}</code></li>
216 * <li>{@link #NEGATIVE_INFINITY} iff
217 * <code>k == {@link Float#NEGATIVE_INFINITY}</code></li>
218 * <li>{@link #NEGATIVE_ZERO} iff <code>k == -0.0</code></li>
219 * <li>{@link #POSITIVE_ZERO} iff <code>k == 0.0</code></li>
220 * </ul>
221 * <p>
222 * Otherwise, the <code>binary16</code> value that most closely represents
223 * <code>k</code> is returned. This may obviously be an infinite value as
224 * the interval of single precision values is far larger than that of the
225 * <code>binary16</code> type.
226 * </p>
227 *
228 * @see #unpackFloat(char)
229 */
230
231 public static char packFloat(
232 final float k)
233 {
234 if (Float.isNaN(k)) {
235 return Binary16.exampleNaN();
236 }
237 if (k == Float.POSITIVE_INFINITY) {
239 }
240 if (k == Float.NEGATIVE_INFINITY) {
242 }
243 if (Float.floatToIntBits(k) == Binary32.NEGATIVE_ZERO_BITS) {
244 return Binary16.NEGATIVE_ZERO;
245 }
246 if (k == 0.0) {
247 return Binary16.POSITIVE_ZERO;
248 }
249
250 final long de = Binary32.unpackGetExponentUnbiased(k);
251 final long ds = Binary32.unpackGetSign(k);
252 final long dn = Binary32.unpackGetSignificand(k);
253 final char rsr = Binary16.packSetSignUnchecked((int) ds);
254
255 /**
256 * Extract the 5 least-significant bits of the exponent.
257 */
258
259 final int rem = (int) (de & 0x001F);
260 final char rer = Binary16.packSetExponentUnbiasedUnchecked(rem);
261
262 /**
263 * Extract the 10 most-significant bits of the significand.
264 */
265
266 final long rnm = dn & 0x7FE000L;
267 final long rns = rnm >> 13;
268 final char rnr = Binary16.packSetSignificandUnchecked((int) rns);
269
270 /**
271 * Combine the results.
272 */
273
274 return (char) (rsr | rer | rnr);
275 }
276
277 /**
278 * <p>
279 * Encode the unbiased exponent <code>e</code>. Values should be in the
280 * range <code>[-15, 16]</code> - values outside of this range will be
281 * truncated.
282 * </p>
283 *
284 * @see #unpackGetExponentUnbiased(char)
285 */
286
288 final int e)
289 {
290 final int eb = e + Binary16.BIAS;
291 final int es = eb << 10;
292 final int em = es & Binary16.MASK_EXPONENT;
293 return (char) em;
294 }
295
296 /**
297 * <p>
298 * Encode the significand <code>s</code>. Values should be in the range
299 * <code>[0, 1023]</code>. Values outside of this range will be truncated.
300 * </p>
301 *
302 * @see #unpackGetSignificand(char)
303 */
304
305 public static char packSetSignificandUnchecked(
306 final int s)
307 {
308 final int sm = s & Binary16.MASK_SIGNIFICAND;
309 return (char) sm;
310 }
311
312 /**
313 * <p>
314 * Encode the sign bit <code>s</code>. Values should be in the range
315 * <code>[0, 1]</code>, with <code>0</code> ironically denoting a positive
316 * value. Values outside of this range will be truncated.
317 * </p>
318 *
319 * @see #unpackGetSign(char)
320 */
321
322 public static char packSetSignUnchecked(
323 final int s)
324 {
325 final int ss = s << 15;
326 final int sm = ss & Binary16.MASK_SIGN;
327 return (char) sm;
328 }
329
330 /**
331 * Show the given raw packed <code>binary16</code> value as a string of
332 * binary digits.
333 */
334
335 public static String toRawBinaryString(
336 final char k)
337 {
338 final StringBuilder b = new StringBuilder();
339 int z = k;
340 for (int i = 0; i < 16; ++i) {
341 if ((z & 1) == 1) {
342 b.insert(0, "1");
343 } else {
344 b.insert(0, "0");
345 }
346 z >>= 1;
347 }
348 return b.toString();
349 }
350
351 /**
352 * <p>
353 * Convert a packed <code>binary16</code> value <code>k</code> to a
354 * double-precision floating point value.
355 * </p>
356 * <p>
357 * The function returns:
358 * </p>
359 * <ul>
360 * <li><code>NaN</code> iff <code>isNaN(k)</code></li>
361 * <li>{@link Double#POSITIVE_INFINITY} iff
362 * <code>k == {@link #POSITIVE_INFINITY}</code></li>
363 * <li>{@link Double#NEGATIVE_INFINITY} iff
364 * <code>k == {@link #NEGATIVE_INFINITY}</code></li>
365 * <li><code>-0.0</code> iff <code>k == {@link #NEGATIVE_ZERO}</code></li>
366 * <li><code>0.0</code> iff <code>k == {@link #POSITIVE_ZERO}</code></li>
367 * <li><code>(-1.0 * n) * (2 ^ e) * 1.s</code>, for the decoded sign
368 * <code>n</code> of <code>k</code>, the decoded exponent <code>e</code> of
369 * <code>k</code>, and the decoded significand <code>s</code> of
370 * <code>k</code>.</li>
371 * </ul>
372 *
373 * @see #packDouble(double)
374 */
375
376 public static double unpackDouble(
377 final char k)
378 {
379 if (Binary16.isNaN(k)) {
380 return Double.NaN;
381 }
382 if (k == Binary16.POSITIVE_INFINITY) {
383 return Double.POSITIVE_INFINITY;
384 }
385 if (k == Binary16.NEGATIVE_INFINITY) {
386 return Double.NEGATIVE_INFINITY;
387 }
388 if (k == Binary16.NEGATIVE_ZERO) {
389 return -0.0;
390 }
391 if (k == Binary16.POSITIVE_ZERO) {
392 return 0.0;
393 }
394
395 final long e = Binary16.unpackGetExponentUnbiased(k);
396 final long s = Binary16.unpackGetSign(k);
397 final long n = Binary16.unpackGetSignificand(k);
398
399 /**
400 * Shift the sign bit to the position at which it will appear in the
401 * resulting value.
402 */
403
404 final long rsr = s << 63;
405
406 /**
407 * 1. Bias the exponent.
408 *
409 * 2. Shift the result left to the position at which it will appear in the
410 * resulting value.
411 */
412
413 final long reb = (e + Binary64.BIAS);
414 final long rer = reb << 52;
415
416 /**
417 * Shift the significand left to the position at which it will appear in
418 * the resulting value.
419 */
420
421 final long rnr = n << 42;
422 return Double.longBitsToDouble(rsr | rer | rnr);
423 }
424
425 /**
426 * <p>
427 * Convert a packed <code>binary16</code> value <code>k</code> to a
428 * single-precision floating point value.
429 * </p>
430 * <p>
431 * The function returns:
432 * </p>
433 * <ul>
434 * <li><code>NaN</code> iff <code>isNaN(k)</code></li>
435 * <li>{@link Float#POSITIVE_INFINITY} iff
436 * <code>k == {@link #POSITIVE_INFINITY}</code></li>
437 * <li>{@link Float#NEGATIVE_INFINITY} iff
438 * <code>k == {@link #NEGATIVE_INFINITY}</code></li>
439 * <li><code>-0.0</code> iff <code>k == {@link #NEGATIVE_ZERO}</code></li>
440 * <li><code>0.0</code> iff <code>k == {@link #POSITIVE_ZERO}</code></li>
441 * <li><code>(-1.0 * n) * (2 ^ e) * 1.s</code>, for the decoded sign
442 * <code>n</code> of <code>k</code>, the decoded exponent <code>e</code> of
443 * <code>k</code>, and the decoded significand <code>s</code> of
444 * <code>k</code>.</li>
445 * </ul>
446 *
447 * @see #packFloat(float)
448 */
449
450 public static float unpackFloat(
451 final char k)
452 {
453 if (Binary16.isNaN(k)) {
454 return Float.NaN;
455 }
456 if (k == Binary16.POSITIVE_INFINITY) {
457 return Float.POSITIVE_INFINITY;
458 }
459 if (k == Binary16.NEGATIVE_INFINITY) {
460 return Float.NEGATIVE_INFINITY;
461 }
462 if (k == Binary16.NEGATIVE_ZERO) {
463 return -0.0f;
464 }
465 if (k == Binary16.POSITIVE_ZERO) {
466 return 0.0f;
467 }
468
469 final int e = Binary16.unpackGetExponentUnbiased(k);
470 final int s = Binary16.unpackGetSign(k);
471 final int n = Binary16.unpackGetSignificand(k);
472
473 /**
474 * Shift the sign bit to the position at which it will appear in the
475 * resulting value.
476 */
477
478 final int rsr = s << 31;
479
480 /**
481 * 1. Bias the exponent.
482 *
483 * 2. Shift the result left to the position at which it will appear in the
484 * resulting value.
485 */
486
487 final int reb = (e + Binary32.BIAS);
488 final int rer = reb << 23;
489
490 /**
491 * Shift the significand left to the position at which it will appear in
492 * the resulting value.
493 */
494
495 final int rnr = n << 13;
496 return Float.intBitsToFloat(rsr | rer | rnr);
497 }
498
499 /**
500 * <p>
501 * Extract and unbias the exponent of the given packed <code>binary16</code>
502 * value.
503 * </p>
504 * <p>
505 * The exponent is encoded <i>biased</i> as a number in the range
506 * <code>[0, 31]</code>, with <code>0</code> indicating that the number is
507 * <i>subnormal</i> and <code>[1, 30]</code> denoting the actual exponent
508 * plus {@link #BIAS}. Infinite and <code>NaN</code> values always have an
509 * exponent of <code>31</code>.
510 * </p>
511 * <p>
512 * This function will therefore return:
513 * </p>
514 * <ul>
515 * <li>
516 * <code>0 - {@link #BIAS} = -15</code> iff the input is a <i>subnormal</i>
517 * number.</li>
518 * <li>An integer in the range
519 * <code>[1 - {@link #BIAS}, 30 - {@link #BIAS}] = [-14, 15]</code> iff the
520 * input is a <i>normal</i> number.</li>
521 * <li>
522 * <code>16</code> iff the input is {@link #POSITIVE_INFINITY},
523 * {@link #NEGATIVE_INFINITY}, or <code>NaN</code>.</li>
524 * </ul>
525 *
526 * @see #packSetExponentUnbiasedUnchecked(int)
527 */
528
529 public static int unpackGetExponentUnbiased(
530 final char k)
531 {
532 final int em = k & Binary16.MASK_EXPONENT;
533 final int es = em >> 10;
534 return es - Binary16.BIAS;
535 }
536
537 /**
538 * Retrieve the sign bit of the given packed <code>binary16</code> value, as
539 * an integer in the range <code>[0, 1]</code>.
540 *
541 * @see Binary16#packSetSignUnchecked(int)
542 */
543
544 public static int unpackGetSign(
545 final char k)
546 {
547 return (k & Binary16.MASK_SIGN) >> 15;
548 }
549
550 /**
551 * <p>
552 * Return the significand of the given packed <code>binary16</code> value as
553 * an integer in the range <code>[0, 1023]</code>.
554 * </p>
555 *
556 * @see Binary16#packSetSignificandUnchecked(int)
557 */
558
559 public static int unpackGetSignificand(
560 final char k)
561 {
562 return k & Binary16.MASK_SIGNIFICAND;
563 }
564
565 private Binary16()
566 {
567 throw new AssertionError("Unreachable code, report this bug!");
568 }
569}
static char packSetExponentUnbiasedUnchecked(final int e)
Definition: Binary16.java:287
static char packSetSignificandUnchecked(final int s)
Definition: Binary16.java:305
static final char NEGATIVE_INFINITY
The encoded form of negative infinity -∞.
Definition: Binary16.java:44
static int unpackGetExponentUnbiased(final char k)
Definition: Binary16.java:529
static char exampleNaN()
One possible not-a-number value.
Definition: Binary16.java:93
static char packDouble(final double k)
Definition: Binary16.java:158
static boolean isNaN(final char k)
Return true if the given packed binary16 value is not a number (NaN).
Definition: Binary16.java:123
static final char POSITIVE_INFINITY
The encoded form of positive infinity ∞.
Definition: Binary16.java:50
static final char NEGATIVE_ZERO
The encoded form of negative zero -0.
Definition: Binary16.java:62
static int unpackGetSignificand(final char k)
Definition: Binary16.java:559
static char packSetSignUnchecked(final int s)
Definition: Binary16.java:322
static final int BIAS
The bias value used to offset the encoded exponent.
Definition: Binary16.java:69
static String toRawBinaryString(final char k)
Show the given raw packed binary16 value as a string of binary digits.
Definition: Binary16.java:335
static char packFloat(final float k)
Definition: Binary16.java:231
static double unpackDouble(final char k)
Definition: Binary16.java:376
static boolean isInfinite(final char k)
Return true if the given packed binary16 value is infinite.
Definition: Binary16.java:107
static final char POSITIVE_ZERO
The encoded form of positive zero 0.
Definition: Binary16.java:56
static int unpackGetSign(final char k)
Retrieve the sign bit of the given packed binary16 value, as an integer in the range [0,...
Definition: Binary16.java:544
static float unpackFloat(final char k)
Definition: Binary16.java:450
Functions for interrogating binary32 (float) values.
Definition: Binary32.java:36
static int unpackGetSign(final float d)
Definition: Binary32.java:97
static int unpackGetExponentUnbiased(final float d)
Definition: Binary32.java:82
static int unpackGetSignificand(final float d)
Definition: Binary32.java:110
Functions for interrogating binary64 (double) values.
Definition: Binary64.java:36
static long unpackGetSign(final double d)
Definition: Binary64.java:110
static long unpackGetExponentUnbiased(final double d)
Definition: Binary64.java:82
static long unpackGetSignificand(final double d)
Definition: Binary64.java:97