1 | // Copyright 2011 the V8 project authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | #ifndef V8_DIY_FP_H_ |
6 | #define V8_DIY_FP_H_ |
7 | |
8 | #include <stdint.h> |
9 | |
10 | #include "src/base/logging.h" |
11 | #include "src/base/macros.h" |
12 | |
13 | namespace v8 { |
14 | namespace internal { |
15 | |
16 | // This "Do It Yourself Floating Point" class implements a floating-point number |
17 | // with a uint64 significand and an int exponent. Normalized DiyFp numbers will |
18 | // have the most significant bit of the significand set. |
19 | // Multiplication and Subtraction do not normalize their results. |
20 | // DiyFp are not designed to contain special doubles (NaN and Infinity). |
21 | class DiyFp { |
22 | public: |
23 | static const int kSignificandSize = 64; |
24 | |
25 | DiyFp() : f_(0), e_(0) {} |
26 | DiyFp(uint64_t f, int e) : f_(f), e_(e) {} |
27 | |
28 | // this = this - other. |
29 | // The exponents of both numbers must be the same and the significand of this |
30 | // must be bigger than the significand of other. |
31 | // The result will not be normalized. |
32 | void Subtract(const DiyFp& other) { |
33 | DCHECK(e_ == other.e_); |
34 | DCHECK(f_ >= other.f_); |
35 | f_ -= other.f_; |
36 | } |
37 | |
38 | // Returns a - b. |
39 | // The exponents of both numbers must be the same and this must be bigger |
40 | // than other. The result will not be normalized. |
41 | static DiyFp Minus(const DiyFp& a, const DiyFp& b) { |
42 | DiyFp result = a; |
43 | result.Subtract(b); |
44 | return result; |
45 | } |
46 | |
47 | |
48 | // this = this * other. |
49 | V8_EXPORT_PRIVATE void Multiply(const DiyFp& other); |
50 | |
51 | // returns a * b; |
52 | static DiyFp Times(const DiyFp& a, const DiyFp& b) { |
53 | DiyFp result = a; |
54 | result.Multiply(b); |
55 | return result; |
56 | } |
57 | |
58 | void Normalize() { |
59 | DCHECK_NE(f_, 0); |
60 | uint64_t f = f_; |
61 | int e = e_; |
62 | |
63 | // This method is mainly called for normalizing boundaries. In general |
64 | // boundaries need to be shifted by 10 bits. We thus optimize for this case. |
65 | const uint64_t k10MSBits = static_cast<uint64_t>(0x3FF) << 54; |
66 | while ((f & k10MSBits) == 0) { |
67 | f <<= 10; |
68 | e -= 10; |
69 | } |
70 | while ((f & kUint64MSB) == 0) { |
71 | f <<= 1; |
72 | e--; |
73 | } |
74 | f_ = f; |
75 | e_ = e; |
76 | } |
77 | |
78 | static DiyFp Normalize(const DiyFp& a) { |
79 | DiyFp result = a; |
80 | result.Normalize(); |
81 | return result; |
82 | } |
83 | |
84 | uint64_t f() const { return f_; } |
85 | int e() const { return e_; } |
86 | |
87 | void set_f(uint64_t new_value) { f_ = new_value; } |
88 | void set_e(int new_value) { e_ = new_value; } |
89 | |
90 | private: |
91 | static const uint64_t kUint64MSB = static_cast<uint64_t>(1) << 63; |
92 | |
93 | uint64_t f_; |
94 | int e_; |
95 | }; |
96 | |
97 | } // namespace internal |
98 | } // namespace v8 |
99 | |
100 | #endif // V8_DIY_FP_H_ |
101 | |