floor.mx raw

   1  // Copyright 2009 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  package math
   6  
   7  // Floor returns the greatest integer value less than or equal to x.
   8  //
   9  // Special cases are:
  10  //
  11  //	Floor(±0) = ±0
  12  //	Floor(±Inf) = ±Inf
  13  //	Floor(NaN) = NaN
  14  func Floor(x float64) float64 {
  15  	if haveArchFloor {
  16  		return archFloor(x)
  17  	}
  18  	return floor(x)
  19  }
  20  
  21  func floor(x float64) float64 {
  22  	if x == 0 || IsNaN(x) || IsInf(x, 0) {
  23  		return x
  24  	}
  25  	if x < 0 {
  26  		d, fract := Modf(-x)
  27  		if fract != 0.0 {
  28  			d = d + 1
  29  		}
  30  		return -d
  31  	}
  32  	d, _ := Modf(x)
  33  	return d
  34  }
  35  
  36  // Ceil returns the least integer value greater than or equal to x.
  37  //
  38  // Special cases are:
  39  //
  40  //	Ceil(±0) = ±0
  41  //	Ceil(±Inf) = ±Inf
  42  //	Ceil(NaN) = NaN
  43  func Ceil(x float64) float64 {
  44  	if haveArchCeil {
  45  		return archCeil(x)
  46  	}
  47  	return ceil(x)
  48  }
  49  
  50  func ceil(x float64) float64 {
  51  	return -Floor(-x)
  52  }
  53  
  54  // Trunc returns the integer value of x.
  55  //
  56  // Special cases are:
  57  //
  58  //	Trunc(±0) = ±0
  59  //	Trunc(±Inf) = ±Inf
  60  //	Trunc(NaN) = NaN
  61  func Trunc(x float64) float64 {
  62  	if haveArchTrunc {
  63  		return archTrunc(x)
  64  	}
  65  	return trunc(x)
  66  }
  67  
  68  func trunc(x float64) float64 {
  69  	if x == 0 || IsNaN(x) || IsInf(x, 0) {
  70  		return x
  71  	}
  72  	d, _ := Modf(x)
  73  	return d
  74  }
  75  
  76  // Round returns the nearest integer, rounding half away from zero.
  77  //
  78  // Special cases are:
  79  //
  80  //	Round(±0) = ±0
  81  //	Round(±Inf) = ±Inf
  82  //	Round(NaN) = NaN
  83  func Round(x float64) float64 {
  84  	// Round is a faster implementation of:
  85  	//
  86  	// func Round(x float64) float64 {
  87  	//   t := Trunc(x)
  88  	//   if Abs(x-t) >= 0.5 {
  89  	//     return t + Copysign(1, x)
  90  	//   }
  91  	//   return t
  92  	// }
  93  	bits := Float64bits(x)
  94  	e := uint(bits>>shift) & mask
  95  	if e < bias {
  96  		// Round abs(x) < 1 including denormals.
  97  		bits &= signMask // +-0
  98  		if e == bias-1 {
  99  			bits |= uvone // +-1
 100  		}
 101  	} else if e < bias+shift {
 102  		// Round any abs(x) >= 1 containing a fractional component [0,1).
 103  		//
 104  		// Numbers with larger exponents are returned unchanged since they
 105  		// must be either an integer, infinity, or NaN.
 106  		const half = 1 << (shift - 1)
 107  		e -= bias
 108  		bits += half >> e
 109  		bits &^= fracMask >> e
 110  	}
 111  	return Float64frombits(bits)
 112  }
 113  
 114  // RoundToEven returns the nearest integer, rounding ties to even.
 115  //
 116  // Special cases are:
 117  //
 118  //	RoundToEven(±0) = ±0
 119  //	RoundToEven(±Inf) = ±Inf
 120  //	RoundToEven(NaN) = NaN
 121  func RoundToEven(x float64) float64 {
 122  	// RoundToEven is a faster implementation of:
 123  	//
 124  	// func RoundToEven(x float64) float64 {
 125  	//   t := math.Trunc(x)
 126  	//   odd := math.Remainder(t, 2) != 0
 127  	//   if d := math.Abs(x - t); d > 0.5 || (d == 0.5 && odd) {
 128  	//     return t + math.Copysign(1, x)
 129  	//   }
 130  	//   return t
 131  	// }
 132  	bits := Float64bits(x)
 133  	e := uint(bits>>shift) & mask
 134  	if e >= bias {
 135  		// Round abs(x) >= 1.
 136  		// - Large numbers without fractional components, infinity, and NaN are unchanged.
 137  		// - Add 0.499.. or 0.5 before truncating depending on whether the truncated
 138  		//   number is even or odd (respectively).
 139  		const halfMinusULP = (1 << (shift - 1)) - 1
 140  		e -= bias
 141  		bits += (halfMinusULP + (bits>>(shift-e))&1) >> e
 142  		bits &^= fracMask >> e
 143  	} else if e == bias-1 && bits&fracMask != 0 {
 144  		// Round 0.5 < abs(x) < 1.
 145  		bits = bits&signMask | uvone // +-1
 146  	} else {
 147  		// Round abs(x) <= 0.5 including denormals.
 148  		bits &= signMask // +-0
 149  	}
 150  	return Float64frombits(bits)
 151  }
 152