public inbox for frysk-cvs@sourceware.org help / color / mirror / Atom feed
From: tthomas@sourceware.org To: frysk-cvs@sourceware.org Subject: [SCM] master: Create unit to pack IEEE 754/854 floating point into BigDecimal. Date: Mon, 10 Dec 2007 21:37:00 -0000 [thread overview] Message-ID: <20071210213723.5703.qmail@sourceware.org> (raw) The branch, master has been updated via b26d3ca6ff01019e0287fc89f2eedf0d6879d8ff (commit) from 4581f27bd20fc5b8f30e181ec4e0d22af79f510b (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email. - Log ----------------------------------------------------------------- commit b26d3ca6ff01019e0287fc89f2eedf0d6879d8ff Author: Teresa <tthomas@redhat.com> Date: Mon Dec 10 16:33:08 2007 -0500 Create unit to pack IEEE 754/854 floating point into BigDecimal. frysk-core/frysk/value/ChangeLog 2007-12-10 Teresa Thomas <tthomas@redhat.com> * TestBigFloatingPoint.java: New. * BigFloatingPoint.java: New. ----------------------------------------------------------------------- Summary of changes: frysk-core/frysk/value/BigFloatingPoint.java | 234 ++++++++++++++++++++++ frysk-core/frysk/value/ChangeLog | 5 + frysk-core/frysk/value/TestBigFloatingPoint.java | 199 ++++++++++++++++++ 3 files changed, 438 insertions(+), 0 deletions(-) create mode 100644 frysk-core/frysk/value/BigFloatingPoint.java create mode 100644 frysk-core/frysk/value/TestBigFloatingPoint.java First 500 lines of diff: diff --git a/frysk-core/frysk/value/BigFloatingPoint.java b/frysk-core/frysk/value/BigFloatingPoint.java new file mode 100644 index 0000000..b90f5d3 --- /dev/null +++ b/frysk-core/frysk/value/BigFloatingPoint.java @@ -0,0 +1,234 @@ +// This file is part of the program FRYSK. +// +// Copyright 2007, Red Hat Inc. +// +// FRYSK is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// FRYSK is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with FRYSK; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// +// In addition, as a special exception, Red Hat, Inc. gives You the +// additional right to link the code of FRYSK with code not covered +// under the GNU General Public License ("Non-GPL Code") and to +// distribute linked combinations including the two, subject to the +// limitations in this paragraph. Non-GPL Code permitted under this +// exception must only link to the code of FRYSK through those well +// defined interfaces identified in the file named EXCEPTION found in +// the source code files (the "Approved Interfaces"). The files of +// Non-GPL Code may instantiate templates or use macros or inline +// functions from the Approved Interfaces without causing the +// resulting work to be covered by the GNU General Public +// License. Only Red Hat, Inc. may make changes or additions to the +// list of Approved Interfaces. You must obey the GNU General Public +// License in all respects for all of the FRYSK code and other code +// used in conjunction with FRYSK except the Non-GPL Code covered by +// this exception. If you modify this file, you may extend this +// exception to your version of the file, but you are not obligated to +// do so. If you do not wish to provide this exception without +// modification, you must delete this exception statement from your +// version and license this file solely under the GPL without +// exception. + +package frysk.value; + +import java.math.BigDecimal; +import java.math.BigInteger; + +/** + * Floating point type - uses java.math.BigDecimal. + */ +public class BigFloatingPoint +{ + private BigDecimal value; + private int encoding; + + public static final int proper = 0; + public static final int NaN = 1; + public static final int posInf = 2; + public static final int negInf = 3; + + // Packing objects for each IEEE FP type. + private static final Packing packExponent32 = new Packing (4, 1, 8); + private static final Packing packFraction32 = new Packing (4, 9, 23); + private static final Packing packExponent64 = new Packing (8, 1, 11); + private static final Packing packFraction64 = new Packing (8, 12, 52); + // FIXME: 128 bit long doubles on x86_64 follow 80 bit "format" + private static final Packing packExponent128 = new Packing (16, 1, 15); + private static final Packing packFraction128 = new Packing (16, 16, 112); + private static final Packing packExponent96 = new Packing (12, 1+16, 15); + private static final Packing packFraction96 = new Packing (12, 16+16, 64); + private static final Packing packExponent80 = new Packing (10, 1, 15); + private static final Packing packFraction80 = new Packing (10, 16, 64); + + private static final BigDecimal two = BigDecimal.ONE.add(BigDecimal.ONE); + + /** + * Create a BigFloatingPoint from a BigDecimal. + */ + BigFloatingPoint (BigDecimal value) { + this.value = value; + this.encoding = proper; + } + + /** + * Create a BigFloatingPoint from the big-endian raw + * bytes. bytes[] contain three fields: + * sign, exponent and fraction + */ + BigFloatingPoint (byte[] bytes) { + Packing e; + Packing f; + int maxE; + int sizeofF; + + switch (bytes.length) { + case 4: + e = packExponent32; + f = packFraction32; + sizeofF = 23; + maxE = 0xff; + break; + case 8: + e = packExponent64; + f = packFraction64; + sizeofF = 52; + maxE = 0x7ff; + break; + case 16: + e = packExponent128; + f = packFraction128; + sizeofF = 112; + maxE = 0x7fff; + break; + case 12: + e = packExponent96; + f = packFraction96; + sizeofF = 64; + maxE = 0x7fff; + break; + case 10: + e = packExponent80; + f = packFraction80; + sizeofF = 64; + maxE = 0x7fff; + break; + default: + throw new RuntimeException ("Unsupported Floating Point size"); + } + int s = (((bytes[0] >> 7) & 0x01) == 0) ? -1:1; + + BigDecimal m = getMantissa(f.unpackUnsigned(bytes), + e.unpackUnsigned(bytes), + sizeofF); + calculateValue (s, e.unpackUnsigned(bytes), m, BigInteger.valueOf(maxE)); + } + + /** + * Gets mantissa value according to IEEE 754/854 floating point rules + * + * @param f - value of fraction field (including j bit where applicable) + * @param e - value of exponent field + * @param sizeOfF - bit size of fraction field + * (including j bit where applicable) + * @return mantissa + */ + private BigDecimal getMantissa (BigInteger f, BigInteger e, int sizeOfF) { + if (sizeOfF == 64) + return getMantissaExtended (f, sizeOfF); + + int trailingZeroes = f.getLowestSetBit(); + BigDecimal m = new BigDecimal (f.shiftRight(trailingZeroes)); + m = divide (m, two.pow(sizeOfF-trailingZeroes)); + return (e.compareTo(BigInteger.ZERO) == 0)? m : BigDecimal.ONE.add(m); + } + + private BigDecimal getMantissaExtended (BigInteger f, int sizeOfF){ + int trailingZeroes = f.getLowestSetBit(); + boolean j = f.testBit(f.bitLength()-1); + f = f.clearBit(f.bitLength()-1); + BigDecimal m = new BigDecimal (f.shiftRight(trailingZeroes)); + m = divide (m, two.pow(sizeOfF-trailingZeroes-1)); + return (j == false)? m : BigDecimal.ONE.add(m); + } + + /** + * Calculate floating point value according to IEEE 754/854 rules. + * @param s - sign bit + * @param e - value of exponent field + * @param m - mantissa + * @param maxE - max possible value of exponent field + */ + private void calculateValue (int s, BigInteger e, BigDecimal m, BigInteger maxE) { + BigDecimal result = BigDecimal.ZERO; + BigDecimal one = BigDecimal.ONE; + int halfMaxE = maxE.intValue()/2; + + if (e.compareTo(maxE) == 0) { + if (m.compareTo(BigDecimal.ZERO) != 0) { + // FIXME: Should NaNs retain value of fraction + // or mantissa? + this.value = m; + this.encoding = NaN; + } + else { + // FIXME: Should this retain any value here? + this.value = null; + this.encoding = ( s == -1 )? posInf:negInf; + } + } + else if (e.compareTo(BigInteger.ZERO) == 0) { + if (m.compareTo(BigDecimal.ZERO) != 0) { + result = divide(one, two.pow(halfMaxE-1)).multiply(m); + } + else { + result = BigDecimal.ZERO; + } + this.value = (s == -1)? result:result.negate(); + this.encoding = proper; + } + else if (e.compareTo(BigInteger.ZERO) > 0 && e.compareTo(maxE) < 0) { + if (e.intValue()-halfMaxE < 0) + result = divide (one, two.pow(-e.intValue()+halfMaxE)).multiply(m); + else + result = two.pow(e.intValue()-halfMaxE).multiply(m); + this.value = ( s == -1 )? result:result.negate(); + this.encoding = proper; + } + else { + throw new RuntimeException + ("IEEE 754/854 Floating Point conversion error."); + } + } + + private BigDecimal divide (BigDecimal a, BigDecimal b) { + BigDecimal result[] = a.divideAndRemainder(b); + // FIXME: Use long division? Use BigDecimal's + // divide(BigDecimal,MathContext) when frysk + // moves to java 1.5.0. + double fraction = result[1].doubleValue()/b.doubleValue(); + return result[0].add(BigDecimal.valueOf(fraction)); + } + + BigDecimal getValue () { + return value; + } + + int getEncoding () { + return encoding; + } + + double doubleValue() { + if (encoding == proper) + return value.doubleValue(); + else + return 0; + } +} diff --git a/frysk-core/frysk/value/ChangeLog b/frysk-core/frysk/value/ChangeLog index 0d033cb..deef85e 100644 --- a/frysk-core/frysk/value/ChangeLog +++ b/frysk-core/frysk/value/ChangeLog @@ -1,3 +1,8 @@ +2007-12-10 Teresa Thomas <tthomas@redhat.com> + + * TestBigFloatingPoint.java: New. + * BigFloatingPoint.java: New. + 2007-11-30 Teresa Thomas <tthomas@redhat.com> * TestArray.java (testSlice): Reindent. diff --git a/frysk-core/frysk/value/TestBigFloatingPoint.java b/frysk-core/frysk/value/TestBigFloatingPoint.java new file mode 100644 index 0000000..7ed289f --- /dev/null +++ b/frysk-core/frysk/value/TestBigFloatingPoint.java @@ -0,0 +1,199 @@ +// This file is part of the program FRYSK. +// +// Copyright 2007, Red Hat Inc. +// +// FRYSK is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// FRYSK is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with FRYSK; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// +// In addition, as a special exception, Red Hat, Inc. gives You the +// additional right to link the code of FRYSK with code not covered +// under the GNU General Public License ("Non-GPL Code") and to +// distribute linked combinations including the two, subject to the +// limitations in this paragraph. Non-GPL Code permitted under this +// exception must only link to the code of FRYSK through those well +// defined interfaces identified in the file named EXCEPTION found in +// the source code files (the "Approved Interfaces"). The files of +// Non-GPL Code may instantiate templates or use macros or inline +// functions from the Approved Interfaces without causing the +// resulting work to be covered by the GNU General Public +// License. Only Red Hat, Inc. may make changes or additions to the +// list of Approved Interfaces. You must obey the GNU General Public +// License in all respects for all of the FRYSK code and other code +// used in conjunction with FRYSK except the Non-GPL Code covered by +// this exception. If you modify this file, you may extend this +// exception to your version of the file, but you are not obligated to +// do so. If you do not wish to provide this exception without +// modification, you must delete this exception statement from your +// version and license this file solely under the GPL without +// exception. + +package frysk.value; + +import java.math.BigDecimal; +import frysk.junit.TestCase; + +public class TestBigFloatingPoint + extends TestCase +{ + /** + * Pass when CORRECT is exactly (i.e., bitwise) equal to TEST. + */ + static void checkEquals(String what, double correct, double test) { + if (Double.doubleToRawLongBits(correct) + != Double.doubleToRawLongBits(test)) { + fail(what + + ": expected <" + correct + ">" + + " got <" + test + ">"); + } + } + + static final byte[] FLOAT_HALF = new byte[] { + 0x3f, 0x00, 0x00, 0x00 + }; + static final byte[] FLOAT_NEGATIVE_ZERO = new byte[] { + (byte)0x80, 0x00, 0x00, 0x00 + }; + static final byte[] FLOAT_POSITIVE_ZERO = new byte[] { + 0x00, 0x00, 0x00, 0x00 + }; + static final byte[] FLOAT_ONE = new byte[] { + 0x3f, (byte)0x80, 0x00, 0x00 + }; + static final byte[] FLOAT_TWO = new byte[] { + 0x40, 0x00, 0x00, 0x00 + }; + static final byte[] FLOAT_NINE = new byte[] { + 0x41, 0x10, 0x00, 0x00 + }; + + static final byte[] DOUBLE_ONE = new byte[] { + 0x3f, (byte)0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static final byte[] DOUBLE_HALF = new byte[] { + 0x3f, (byte)0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static final byte[] DOUBLE_NEGATIVE_ZERO = new byte[] { + (byte)0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static final byte[] DOUBLE_POSITIVE_ZERO = new byte[] { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static final byte[] DOUBLE_TWO = new byte[] { + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static final byte[] DOUBLE_NINE = new byte[] { + 0x40, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static final byte[] DOUBLE_FIVEPOINT769 = new byte[] { + (byte)0xc0, 0x17, 0x13, 0x74, (byte)0xbc, 0x6a, 0x7e, (byte)0xfa + }; + + static final byte[] FP_128_HALF = new byte[] { + 0x3f, (byte)0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static final byte[] FP_128_ONE = new byte[] { + 0x3f, (byte)0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static final byte[] FP_128_NEGATIVE_ZERO = new byte[] { + (byte)0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static final byte[] FP_128_POSITIVE_ZERO = new byte[] { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static final byte[] FP_128_TWO = new byte[] { + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + static final byte[] FP_96_ONE = new byte[] { + 0x00, 0x00, 0x3f, (byte)0xff, (byte)0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + static final byte[] FP_96_NINE = new byte[] { + 0x00, 0x00, 0x40, 0x02, (byte)0x90, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + static final byte[] FP_96_SEVENPOINT5 = new byte[] { + 0x00, 0x00, 0x40, 0x01, (byte)0xf0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + static final byte[] FP_128_SEVENPOINTFIVE = new byte[] { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x01, (byte)0xf0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + }; + static final byte[] FP_128_NEGATIVE_TWO = new byte[] { + (byte)0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + public void testFromBigDecimal() { + BigFloatingPoint f = new BigFloatingPoint(new BigDecimal(1.0)); + checkEquals("float", 1.0, f.doubleValue()); + } + + public void testFromBytes() { + checkEquals("float 1", 1.0, + new BigFloatingPoint(FLOAT_ONE).doubleValue()); + checkEquals("float .5", 0.5, + new BigFloatingPoint(FLOAT_HALF).doubleValue()); + checkEquals("float -0", 0.0, + new BigFloatingPoint(FLOAT_NEGATIVE_ZERO).doubleValue()); + checkEquals("float +0", +0.0, + new BigFloatingPoint(FLOAT_POSITIVE_ZERO).doubleValue()); + checkEquals("float 2", 2.0, + new BigFloatingPoint(FLOAT_TWO).doubleValue()); + checkEquals("float 9", 9.0, + new BigFloatingPoint(FLOAT_NINE).doubleValue()); + + checkEquals("double 1", 1.0, + new BigFloatingPoint(DOUBLE_ONE).doubleValue()); + checkEquals("double .5", 0.5, + new BigFloatingPoint(DOUBLE_HALF).doubleValue()); + checkEquals("double -0", 0.0, + new BigFloatingPoint(DOUBLE_NEGATIVE_ZERO).doubleValue()); + checkEquals("double +0", +0.0, + new BigFloatingPoint(DOUBLE_POSITIVE_ZERO).doubleValue()); + checkEquals("double 2", 2.0, + new BigFloatingPoint(DOUBLE_TWO).doubleValue()); + checkEquals("double 9", 9.0, + new BigFloatingPoint(DOUBLE_NINE).doubleValue()); + checkEquals("double -5.769", -5.769, + new BigFloatingPoint(DOUBLE_FIVEPOINT769).doubleValue()); + + checkEquals("FP_128 1", 1.0, + new BigFloatingPoint(FP_128_ONE).doubleValue()); + checkEquals("FP_128 0.5", 0.5, + new BigFloatingPoint(FP_128_HALF).doubleValue()); + checkEquals("FP_128 -0", 0.0, + new BigFloatingPoint(FP_128_NEGATIVE_ZERO).doubleValue()); + checkEquals("FP_128 +0", 0.0, + new BigFloatingPoint(FP_128_POSITIVE_ZERO).doubleValue()); + checkEquals("FP_128 2.0", 2.0, + new BigFloatingPoint(FP_128_TWO).doubleValue()); + + checkEquals("FP_96 1", 1.0, + new BigFloatingPoint(FP_96_ONE).doubleValue()); + checkEquals("FP_96 9", 9.0, + new BigFloatingPoint(FP_96_NINE).doubleValue()); + checkEquals("FP_96 9", 7.5, + new BigFloatingPoint(FP_96_SEVENPOINT5).doubleValue()); + } +} + hooks/post-receive -- frysk system monitor/debugger
reply other threads:[~2007-12-10 21:37 UTC|newest] Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20071210213723.5703.qmail@sourceware.org \ --to=tthomas@sourceware.org \ --cc=frysk-cvs@sourceware.org \ --cc=frysk@sourceware.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).