github.com/evanw/esbuild@v0.21.4/internal/helpers/float.go (about)

     1  package helpers
     2  
     3  import "math"
     4  
     5  // This wraps float64 math operations. Why does this exist? The Go compiler
     6  // contains some optimizations to take advantage of "fused multiply and add"
     7  // (FMA) instructions on certain processors. These instructions lead to
     8  // different output on those processors, which means esbuild's output is no
     9  // longer deterministic across all platforms. From the Go specification itself
    10  // (https://go.dev/ref/spec#Floating_point_operators):
    11  //
    12  //	An implementation may combine multiple floating-point operations into a
    13  //	single fused operation, possibly across statements, and produce a result
    14  //	that differs from the value obtained by executing and rounding the
    15  //	instructions individually. An explicit floating-point type conversion
    16  //	rounds to the precision of the target type, preventing fusion that would
    17  //	discard that rounding.
    18  //
    19  //	For instance, some architectures provide a "fused multiply and add" (FMA)
    20  //	instruction that computes x*y + z without rounding the intermediate result
    21  //	x*y.
    22  //
    23  // Therefore we need to add explicit type conversions such as "float64(x)" to
    24  // prevent optimizations that break correctness. Rather than adding them on a
    25  // case-by-case basis as real correctness issues are discovered, we instead
    26  // preemptively force them to be added everywhere by using this wrapper type
    27  // for all floating-point math.
    28  type F64 struct {
    29  	value float64
    30  }
    31  
    32  func NewF64(a float64) F64 {
    33  	return F64{value: float64(a)}
    34  }
    35  
    36  func (a F64) Value() float64 {
    37  	return a.value
    38  }
    39  
    40  func (a F64) IsNaN() bool {
    41  	return math.IsNaN(a.value)
    42  }
    43  
    44  func (a F64) Neg() F64 {
    45  	return NewF64(-a.value)
    46  }
    47  
    48  func (a F64) Abs() F64 {
    49  	return NewF64(math.Abs(a.value))
    50  }
    51  
    52  func (a F64) Sin() F64 {
    53  	return NewF64(math.Sin(a.value))
    54  }
    55  
    56  func (a F64) Cos() F64 {
    57  	return NewF64(math.Cos(a.value))
    58  }
    59  
    60  func (a F64) Log2() F64 {
    61  	return NewF64(math.Log2(a.value))
    62  }
    63  
    64  func (a F64) Round() F64 {
    65  	return NewF64(math.Round(a.value))
    66  }
    67  
    68  func (a F64) Floor() F64 {
    69  	return NewF64(math.Floor(a.value))
    70  }
    71  
    72  func (a F64) Ceil() F64 {
    73  	return NewF64(math.Ceil(a.value))
    74  }
    75  
    76  func (a F64) Squared() F64 {
    77  	return a.Mul(a)
    78  }
    79  
    80  func (a F64) Cubed() F64 {
    81  	return a.Mul(a).Mul(a)
    82  }
    83  
    84  func (a F64) Sqrt() F64 {
    85  	return NewF64(math.Sqrt(a.value))
    86  }
    87  
    88  func (a F64) Cbrt() F64 {
    89  	return NewF64(math.Cbrt(a.value))
    90  }
    91  
    92  func (a F64) Add(b F64) F64 {
    93  	return NewF64(a.value + b.value)
    94  }
    95  
    96  func (a F64) AddConst(b float64) F64 {
    97  	return NewF64(a.value + b)
    98  }
    99  
   100  func (a F64) Sub(b F64) F64 {
   101  	return NewF64(a.value - b.value)
   102  }
   103  
   104  func (a F64) SubConst(b float64) F64 {
   105  	return NewF64(a.value - b)
   106  }
   107  
   108  func (a F64) Mul(b F64) F64 {
   109  	return NewF64(a.value * b.value)
   110  }
   111  
   112  func (a F64) MulConst(b float64) F64 {
   113  	return NewF64(a.value * b)
   114  }
   115  
   116  func (a F64) Div(b F64) F64 {
   117  	return NewF64(a.value / b.value)
   118  }
   119  
   120  func (a F64) DivConst(b float64) F64 {
   121  	return NewF64(a.value / b)
   122  }
   123  
   124  func (a F64) Pow(b F64) F64 {
   125  	return NewF64(math.Pow(a.value, b.value))
   126  }
   127  
   128  func (a F64) PowConst(b float64) F64 {
   129  	return NewF64(math.Pow(a.value, b))
   130  }
   131  
   132  func (a F64) Atan2(b F64) F64 {
   133  	return NewF64(math.Atan2(a.value, b.value))
   134  }
   135  
   136  func (a F64) WithSignFrom(b F64) F64 {
   137  	return NewF64(math.Copysign(a.value, b.value))
   138  }
   139  
   140  func Min2(a F64, b F64) F64 {
   141  	return NewF64(math.Min(a.value, b.value))
   142  }
   143  
   144  func Max2(a F64, b F64) F64 {
   145  	return NewF64(math.Max(a.value, b.value))
   146  }
   147  
   148  func Min3(a F64, b F64, c F64) F64 {
   149  	return NewF64(math.Min(math.Min(a.value, b.value), c.value))
   150  }
   151  
   152  func Max3(a F64, b F64, c F64) F64 {
   153  	return NewF64(math.Max(math.Max(a.value, b.value), c.value))
   154  }
   155  
   156  func Lerp(a F64, b F64, t F64) F64 {
   157  	return b.Sub(a).Mul(t).Add(a)
   158  }