Skip to content

Commit 66db95a

Browse files
Fix mishandling of abs and sign for float and double
1 parent a1b4cc3 commit 66db95a

File tree

1 file changed

+32
-13
lines changed

1 file changed

+32
-13
lines changed

InlineNumeric.scala

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,12 @@ trait InlineNumeric[T] extends Ordering[T]: // extends Numeric[T] // TODO can we
1515
transparent inline def toLong(inline x: T): Long
1616
transparent inline def toFloat(inline x: T): Float
1717
transparent inline def toDouble(inline x: T): Double
18+
transparent inline def abs(inline x: T): T
19+
transparent inline def sign(inline x: T): T
1820

1921
transparent inline def zero = fromInt(0)
2022
transparent inline def one = fromInt(1)
2123

22-
transparent inline def abs(inline x: T): T = if lt(x, zero) then negate(x) else x
23-
24-
transparent inline def sign(inline x: T): T =
25-
if lt(x, zero) then negate(one)
26-
else if gt(x, zero) then one
27-
else zero
28-
2924
object InlineNumeric:
3025
extension [T](inline x: T)(using inline num: InlineNumeric[T])
3126
transparent inline def +(inline y: T): T = num.plus(x, y)
@@ -36,12 +31,16 @@ object InlineNumeric:
3631
transparent inline def toLong: Long = num.toLong(x)
3732
transparent inline def toFloat: Float = num.toFloat(x)
3833
transparent inline def toDouble: Double = num.toDouble(x)
39-
4034
transparent inline def abs: T = num.abs(x)
41-
4235
transparent inline def sign: T = num.sign(x)
4336

4437
trait InlineIntegral[T] extends InlineNumeric[T]:
38+
transparent inline def abs(inline x: T): T = if lt(x, zero) then negate(x) else x
39+
transparent inline def sign(inline x: T): T =
40+
if lt(x, zero) then negate(one)
41+
else if gt(x, zero) then one
42+
else zero
43+
4544
transparent inline def quot(inline x: T, inline y: T): T
4645
transparent inline def rem(inline x: T, inline y: T): T
4746

@@ -53,7 +52,16 @@ object InlineIntegral:
5352
transparent inline def /%(inline rhs: T) = (int.quot(lhs, rhs), int.rem(lhs, rhs))
5453

5554
trait InlineFractional[T] extends InlineNumeric[T]:
55+
transparent inline def abs(inline x: T): T = if lt(x, zero) || isNegZero(x) then negate(x) else x
56+
transparent inline def sign(inline x: T): T =
57+
if isNaN(x) || isNegZero(x) then x
58+
else if lt(x, zero) then negate(one)
59+
else if gt(x, zero) then one
60+
else zero
61+
5662
transparent inline def div(inline x: T, inline y: T): T
63+
protected transparent inline def isNaN(inline x: T): Boolean
64+
protected transparent inline def isNegZero(inline x: T): Boolean
5765

5866
object InlineFractional:
5967
// TODO: how are these imported/composed with Numeric/Fractional. Should the extension methods be defined in trait InlineFractional?
@@ -163,6 +171,8 @@ given FloatIsInlineFractional: InlineFractional[Float] with Ordering.Float.IeeeO
163171
transparent inline def toDouble(inline x: Float): Double = x.toDouble
164172

165173
transparent inline def div(inline x: Float, inline y: Float): Float = x / y
174+
protected transparent inline def isNaN(inline x: Float): Boolean = x.isNaN
175+
protected transparent inline def isNegZero(inline x: Float): Boolean = x.equals(-0f)
166176

167177
given DoubleIsInlineFractional: InlineFractional[Double] with Ordering.Double.IeeeOrdering with
168178
transparent inline def plus(inline x: Double, inline y: Double): Double = x + y
@@ -177,6 +187,8 @@ given DoubleIsInlineFractional: InlineFractional[Double] with Ordering.Double.Ie
177187
transparent inline def toDouble(inline x: Double): Double = x
178188

179189
transparent inline def div(inline x: Double, inline y: Double): Double = x / y
190+
protected transparent inline def isNaN(inline x: Double): Boolean = x.isNaN
191+
protected transparent inline def isNegZero(inline x: Double): Boolean = x.equals(-0.0)
180192

181193
trait BigDecimalIsConflicted extends InlineNumeric[BigDecimal] with Ordering.BigDecimalOrdering:
182194
transparent inline def plus(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x + y
@@ -192,6 +204,9 @@ trait BigDecimalIsConflicted extends InlineNumeric[BigDecimal] with Ordering.Big
192204

193205
given BigDecimalIsInlineFractional: BigDecimalIsConflicted with InlineFractional[BigDecimal] with
194206
transparent inline def div(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x / y
207+
protected transparent inline def isNaN(inline x: BigDecimal): Boolean = false
208+
protected transparent inline def isNegZero(inline x: BigDecimal): Boolean = false
209+
195210

196211
given BigDecimalAsIfInlineIntegral: BigDecimalIsConflicted with InlineIntegral[BigDecimal] with
197212
transparent inline def quot(inline x: BigDecimal, inline y: BigDecimal): BigDecimal = x quot y
@@ -214,7 +229,8 @@ object tests:
214229

215230
inline def bar[T: InlineNumeric](a: T) = a.toInt
216231

217-
inline def sign[T: InlineNumeric](a: T) = a.sign
232+
inline def signInt[T: InlineIntegral](a: T) = a.sign
233+
inline def signFrac[T: InlineFractional](a: T) = a.sign
218234

219235
def test(a: Int, b: Int) =
220236
foo(a, b) // should be a + b * b // can check with -Xprint:inlining
@@ -226,6 +242,9 @@ object tests:
226242
bar(a.toFloat) // should be a.toFloat.toInt
227243
bar(a) // should be a
228244

229-
sign(a)
230-
sign(a.toChar)
231-
sign(-7F)
245+
signInt(a)
246+
signInt(a.toChar)
247+
signFrac(-7F)
248+
249+
signInt(BigDecimal(a))
250+
signFrac(BigDecimal(a)) // the condition with isNan() should be removed

0 commit comments

Comments
 (0)