1/*
2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26// This file is available under and governed by the GNU General Public
27// License version 2 only, as published by the Free Software Foundation.
28// However, the following notice accompanied the original version of this
29// file:
30//
31// Copyright 2010 the V8 project authors. All rights reserved.
32// Redistribution and use in source and binary forms, with or without
33// modification, are permitted provided that the following conditions are
34// met:
35//
36//     * Redistributions of source code must retain the above copyright
37//       notice, this list of conditions and the following disclaimer.
38//     * Redistributions in binary form must reproduce the above
39//       copyright notice, this list of conditions and the following
40//       disclaimer in the documentation and/or other materials provided
41//       with the distribution.
42//     * Neither the name of Google Inc. nor the names of its
43//       contributors may be used to endorse or promote products derived
44//       from this software without specific prior written permission.
45//
46// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
47// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
48// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
49// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
50// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
51// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
52// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
53// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
54// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
55// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
56// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57
58package jdk.nashorn.internal.runtime.doubleconv;
59
60// This "Do It Yourself Floating Point" class implements a floating-point number
61// with a uint64 significand and an int exponent. Normalized DiyFp numbers will
62// have the most significant bit of the significand set.
63// Multiplication and Subtraction do not normalize their results.
64// DiyFp are not designed to contain special doubles (NaN and Infinity).
65class DiyFp {
66
67    private long f_;
68    private int e_;
69
70    static final int kSignificandSize = 64;
71    static final long kUint64MSB = 0x8000000000000000L;
72
73
74    DiyFp() {
75        this.f_ = 0;
76        this.e_ = 0;
77    }
78
79    DiyFp(final long f, final int e) {
80        this.f_ = f;
81        this.e_ = e;
82    }
83
84    // this = this - other.
85    // The exponents of both numbers must be the same and the significand of this
86    // must be bigger than the significand of other.
87    // The result will not be normalized.
88    void subtract(final DiyFp other) {
89        assert (e_ == other.e_);
90        assert Long.compareUnsigned(f_, other.f_) >= 0;
91        f_ -= other.f_;
92    }
93
94    // Returns a - b.
95    // The exponents of both numbers must be the same and this must be bigger
96    // than other. The result will not be normalized.
97    static DiyFp minus(final DiyFp a, final DiyFp b) {
98        final DiyFp result = new DiyFp(a.f_, a.e_);
99        result.subtract(b);
100        return result;
101    }
102
103
104    // this = this * other.
105    final void multiply(final DiyFp other) {
106        // Simply "emulates" a 128 bit multiplication.
107        // However: the resulting number only contains 64 bits. The least
108        // significant 64 bits are only used for rounding the most significant 64
109        // bits.
110        final long kM32 = 0xFFFFFFFFL;
111        final long a = f_ >>> 32;
112        final long b = f_ & kM32;
113        final long c = other.f_ >>> 32;
114        final long d = other.f_ & kM32;
115        final long ac = a * c;
116        final long bc = b * c;
117        final long ad = a * d;
118        final long bd = b * d;
119        long tmp = (bd >>> 32) + (ad & kM32) + (bc & kM32);
120        // By adding 1U << 31 to tmp we round the final result.
121        // Halfway cases will be round up.
122        tmp += 1L << 31;
123        final long result_f = ac + (ad >>> 32) + (bc >>> 32) + (tmp >>> 32);
124        e_ += other.e_ + 64;
125        f_ = result_f;
126    }
127
128    // returns a * b;
129    static DiyFp times(final DiyFp a, final DiyFp b) {
130        final DiyFp result = new DiyFp(a.f_, a.e_);
131        result.multiply(b);
132        return result;
133    }
134
135    void normalize() {
136        assert(f_ != 0);
137        long significand = this.f_;
138        int exponent = this.e_;
139
140        // This method is mainly called for normalizing boundaries. In general
141        // boundaries need to be shifted by 10 bits. We thus optimize for this case.
142        final long k10MSBits = 0xFFC00000L << 32;
143        while ((significand & k10MSBits) == 0) {
144            significand <<= 10;
145            exponent -= 10;
146        }
147        while ((significand & kUint64MSB) == 0) {
148            significand <<= 1;
149            exponent--;
150        }
151        this.f_ = significand;
152        this.e_ = exponent;
153    }
154
155    static DiyFp normalize(final DiyFp a) {
156        final DiyFp result = new DiyFp(a.f_, a.e_);
157        result.normalize();
158        return result;
159    }
160
161    long f() { return f_; }
162    int e() { return e_; }
163
164    void setF(final long new_value) { f_ = new_value; }
165    void setE(final int new_value) { e_ = new_value; }
166
167    @Override
168    public String toString() {
169        return "DiyFp[f=" + f_ + ", e=" + e_ + "]";
170    }
171
172}
173