Skip to content

Commit f08ee12

Browse files
committed
stdlib/FloatingPoint: add APIs to handle special floating point values
See IEEEFloatingPointNumber protocol for a full list of new APIs and documentation. Swift SVN r10826
1 parent cae5eba commit f08ee12

File tree

2 files changed

+462
-0
lines changed

2 files changed

+462
-0
lines changed

stdlib/core/FloatingPoint.gyb

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,63 @@ def cFuncSuffix(bits):
4747
if bits == 80:
4848
return 'l'
4949

50+
def llvmIntrinsicSuffix(bits):
51+
if bits == 32:
52+
return 'f32'
53+
if bits == 64:
54+
return 'f64'
55+
if bits == 80:
56+
return 'f80'
57+
58+
def getInfBitPattern(bits):
59+
if bits == 32:
60+
return '0x7f800000'
61+
if bits == 64:
62+
return '0x7ff0000000000000'
63+
return 'error'
64+
65+
def getQuietNaNBitPattern(bits):
66+
if bits == 32:
67+
return '0x7fc00000'
68+
if bits == 64:
69+
return '0x7ff8000000000000'
70+
return 'error'
71+
72+
def getSignalingNanBitPattern(bits):
73+
if bits == 32:
74+
return '0x7fa00000'
75+
if bits == 64:
76+
return '0x7ff4000000000000'
77+
return 'error'
78+
79+
def getMinNormalBitPattern(bits):
80+
if bits == 32:
81+
return '0x00800000'
82+
if bits == 64:
83+
return '0x0010000000000000'
84+
return 'error'
85+
86+
def getExponentBitCount(bits):
87+
if bits == 32:
88+
return '8'
89+
if bits == 64:
90+
return '11'
91+
return 'error'
92+
93+
def getSignificantBitCount(bits):
94+
if bits == 32:
95+
return '23'
96+
if bits == 64:
97+
return '52'
98+
return 'error'
99+
100+
def getInfinityExponent(bits):
101+
if bits == 32:
102+
return '0xff'
103+
if bits == 64:
104+
return '0x7ff'
105+
return 'error'
106+
50107
}@
51108

52109
@ for bits in allFloatBits:
@@ -75,6 +132,150 @@ struct ${Self} : ReplPrintable {
75132
}
76133
}
77134

135+
@ if bits in allIntBits:
136+
// Not transparent because the compiler crashes in that case.
137+
//@@transparent
138+
extension ${Self} : IEEEFloatingPointNumber {
139+
typealias _BitsType = UInt${bits}
140+
141+
static func _fromBitPattern(bits: _BitsType) -> ${Self} {
142+
return ${Self}(Builtin.bitcast_Int${bits}_FPIEEE${bits}(bits.value))
143+
}
144+
145+
func _toBitPattern() -> _BitsType {
146+
return _BitsType(Builtin.bitcast_FPIEEE${bits}_Int${bits}(value))
147+
}
148+
149+
func __getSignBit() -> Int {
150+
return Int(_toBitPattern() >> ${bits - 1}) & 1
151+
}
152+
153+
func __getBiasedExponent() -> _BitsType {
154+
return (_toBitPattern() >> ${getSignificantBitCount(bits)}) & ${getInfinityExponent(bits)}
155+
}
156+
157+
func __getSignificand() -> _BitsType {
158+
var mask: _BitsType = (1 << ${getSignificantBitCount(bits)}) - 1
159+
return _toBitPattern() & mask
160+
}
161+
162+
static func inf() -> ${Self} {
163+
return _fromBitPattern(${getInfBitPattern(bits)})
164+
}
165+
166+
static func NaN() -> ${Self} {
167+
return quietNaN()
168+
}
169+
170+
static func quietNaN() -> ${Self} {
171+
return _fromBitPattern(${getQuietNaNBitPattern(bits)})
172+
}
173+
174+
static func signalingNaN() -> ${Self} {
175+
return _fromBitPattern(${getSignalingNanBitPattern(bits)})
176+
}
177+
178+
func isSignMinus() -> Bool {
179+
return __getSignBit() == 1
180+
}
181+
182+
func isNormal() -> Bool {
183+
var biasedExponent = __getBiasedExponent()
184+
return biasedExponent != ${getInfinityExponent(bits)} &&
185+
biasedExponent != 0
186+
}
187+
188+
func isFinite() -> Bool {
189+
return __getBiasedExponent() != ${getInfinityExponent(bits)}
190+
}
191+
192+
func isZero() -> Bool {
193+
// Mask out the sign bit.
194+
var mask: _BitsType = (1 << (${bits} - 1)) - 1
195+
return (_toBitPattern() & mask) == 0
196+
}
197+
198+
func isSubnormal() -> Bool {
199+
if __getBiasedExponent() == 0 {
200+
return __getSignificand() != 0
201+
}
202+
return false
203+
204+
// Alternative implementation:
205+
// return !isNan() &&
206+
// abs(self) < ${Self}._fromBitPattern(${getMinNormalBitPattern(bits)})
207+
//
208+
// But because we need to check for !isNan(), and do it safely in case of
209+
// SNaN, we need to go down to the bit level, so open-coding the combined
210+
// condition is going to be faster.
211+
}
212+
213+
func isInfinite() -> Bool {
214+
if __getBiasedExponent() == ${getInfinityExponent(bits)} {
215+
return __getSignificand() == 0
216+
}
217+
return false
218+
219+
// Alternative implementation that is not safe in case of SNaN:
220+
// return abs(self) == ${Self}.inf()
221+
}
222+
223+
func isNaN() -> Bool {
224+
if __getBiasedExponent() == ${getInfinityExponent(bits)} {
225+
return __getSignificand() != 0
226+
}
227+
return false
228+
229+
// Alternative implementation that is not safe in case of SNaN:
230+
// return self != self
231+
}
232+
233+
func isSignaling() -> Bool {
234+
if __getBiasedExponent() == ${getInfinityExponent(bits)} {
235+
// IEEE-754R 2008 6.2.1: A signaling NaN bit string should be encoded
236+
// with the first bit of the trailing significand being 0. If the first
237+
// bit of the trailing significand field is 0, some other bit of the
238+
// trailing significand field must be non-zero to distinguish the NaN
239+
// from infinity.
240+
var significand = __getSignificand()
241+
if significand != 0 {
242+
return (significand >> (${getSignificantBitCount(bits)} - 1)) == 0
243+
}
244+
}
245+
return false
246+
}
247+
}
248+
249+
// Not @transparent because the function is too complex.
250+
extension ${Self} /* : IEEEFloatingPointNumber */ {
251+
var floatingPointClass: IEEEFloatingPointClass {
252+
get:
253+
var biasedExponent = __getBiasedExponent()
254+
if biasedExponent == ${getInfinityExponent(bits)} {
255+
var significand = __getSignificand()
256+
// This is either +/-inf or NaN.
257+
if significand == 0 {
258+
return isSignMinus() ? .NegativeInfinity : .PositiveInfinity
259+
}
260+
var isQNaN = (significand >> (${getSignificantBitCount(bits)} - 1)) == 1
261+
return isQNaN ? .QuietNaN : .SignalingNaN
262+
}
263+
264+
// OK, the number is finite.
265+
var isMinus = isSignMinus()
266+
if biasedExponent != 0 {
267+
return isMinus ? .NegativeNormal : .PositiveNormal
268+
}
269+
270+
// Exponent is zero.
271+
if __getSignificand() == 0 {
272+
return isMinus ? .NegativeZero : .PositiveZero
273+
}
274+
return isMinus ? .NegativeSubnormal : .PositiveSubnormal
275+
}
276+
}
277+
@ end
278+
78279
@@transparent
79280
extension ${Self} : BuiltinIntegerLiteralConvertible, IntegerLiteralConvertible {
80281
static func _convertFromBuiltinIntegerLiteral(val: Builtin.Int${builtinIntLiteralBits}) -> ${Self} {

0 commit comments

Comments
 (0)