All files / src/util math.coffee

88.52% Statements 54/61
50% Branches 15/30
100% Functions 9/9
88.33% Lines 53/60

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 1367x 1x 1x   1x 1x 1x 1x 1x 1x 1x 1x 1x     1x 2x 1x 1x 6x   1x 8x 2x 2x 8694x   1x 92x         2x   90x 90x   1x 90x   1x   1x     5x           5x         4x     19x 19x         1x     5x           5x         4x     13x 13x         1x                           1x                             1x       307x 307x     2x   305x 305x 305x   305x 305x    
{ Exception } = require '../datatypes/exception'
{ DateTime } = require '../datatypes/datetime'
{ Uncertainty } = require '../datatypes/uncertainty'
 
module.exports.MAX_INT_VALUE = MAX_INT_VALUE = Math.pow(2,31)-1
module.exports.MIN_INT_VALUE = MIN_INT_VALUE = Math.pow(-2,31)
module.exports.MAX_FLOAT_VALUE = MAX_FLOAT_VALUE = 99999999999999999999999999999.99999999
module.exports.MIN_FLOAT_VALUE = MIN_FLOAT_VALUE = -99999999999999999999999999999.99999999
module.exports.MIN_FLOAT_PRECISION_VALUE = MIN_FLOAT_PRECISION_VALUE = Math.pow(10,-8)
module.exports.MIN_DATE_VALUE = MIN_DATE_VALUE = DateTime.parse("0001-01-01T00:00:00.000")
module.exports.MAX_DATE_VALUE = MAX_DATE_VALUE = DateTime.parse("9999-12-31T23:59:59.999")
module.exports.MIN_TIME_VALUE = MIN_TIME_VALUE = DateTime.parse("0000-01-01T00:00:00.000")
module.exports.MAX_TIME_VALUE = MAX_TIME_VALUE = DateTime.parse("0000-01-01T23:59:59.999")
 
 
module.exports.isValidInteger = isValidInteger = (integer) ->
  return false if isNaN(integer)
  return false if integer > MAX_INT_VALUE
  return false if integer < MIN_INT_VALUE
  return true
 
module.exports.isValidDecimal = isValidDecimal = (decimal) ->
  return false if isNaN(decimal)
  return false if decimal > MAX_FLOAT_VALUE
  return false if decimal < MIN_FLOAT_VALUE
  return true
 
module.exports.limitDecimalPrecision = (decimal) ->
  decimalString = decimal.toString()
  # For decimals so large that they are represented in scientific notation, javascript has already limited
  # the decimal to its own constraints, so we can't determine the original precision.  Leave as-is unless
  # this becomes problematic, in which case we would need our own parseFloat.
  if decimalString.indexOf('e') != -1
    return decimal
 
  splitDecimalString = decimalString.split('.')
  decimalPoints = splitDecimalString[1]
  if decimalPoints? and decimalPoints.length > 8
    decimalString = splitDecimalString[0] + '.' + splitDecimalString[1].substring(0,8)
  return parseFloat(decimalString)
 
module.exports.OverFlowException = OverFlowException = class OverFlowException extends Exception
 
module.exports.successor = successor = (val) ->
  if typeof val is "number"
    if parseInt(val) is val
      if val is MAX_INT_VALUE then throw  new OverFlowException() else val + 1
    else
      #not bothering with the max float test because javascript does not handle floats at the level
      #very well
      val + MIN_FLOAT_PRECISION_VALUE
  else if val instanceof DateTime
    if val.sameAs(MAX_DATE_VALUE) then throw new OverFlowException() else val.successor()
  else if val?.isDate
    if val.sameAs(MAX_DATE_VALUE.getDate()) then throw new OverFlowException() else val.successor()
  else if val instanceof Uncertainty
    # For uncertainties, if the high is the max val, don't increment it
    high = try successor val.high; catch e then val.high
    new Uncertainty(successor(val.low), high)
  else if val?.isQuantity
    succ = val.clone()
    succ.value = successor val.value
    succ
  else if not val?
    null
 
module.exports.predecessor = predecessor = (val) ->
  if typeof val is "number"
    if parseInt(val) is val
      if val is MIN_INT_VALUE then throw  new OverFlowException() else val - 1
    else
      #not bothering with the min float test because javascript does not handle floats at the level
      #very well
      val - MIN_FLOAT_PRECISION_VALUE
  else if val instanceof DateTime
    if val.sameAs(MIN_DATE_VALUE) then throw new OverFlowException() else val.predecessor()
  else if val?.isDate
    if val.sameAs(MIN_DATE_VALUE.getDate()) then throw new OverFlowException() else val.predecessor()
  else if val instanceof Uncertainty
    # For uncertainties, if the low is the min val, don't decrement it
    low = try predecessor val.low; catch e then val.low
    new Uncertainty(low, predecessor(val.high))
  else if val?.isQuantity
    pred = val.clone()
    pred.value = predecessor val.value
    pred
  else if not val?
    null
 
module.exports.maxValueForInstance = (val) ->
  if typeof val is "number"
    if parseInt(val) is val then MAX_INT_VALUE else MAX_FLOAT_VALUE
  else if val instanceof DateTime
    MAX_DATE_VALUE
  else if val?.isDate
    MAX_DATE_VALUE.getDate()
  else if val?.isQuantity
    val2 = val.clone()
    val2.value = maxValueForInstance val2.value
    val2
  else
    null
 
module.exports.minValueForInstance = (val) ->
  if typeof val is "number"
    if parseInt(val) is val then MIN_INT_VALUE else MIN_FLOAT_VALUE
  else if val instanceof DateTime
    MIN_DATE_VALUE
  else if val?.isDate
    MIN_DATE_VALUE.getDate()
  else if val?.isQuantity
    val2 = val.clone()
    val2.value = minValueForInstance val2.value
    val2
  else
    null
 
 
module.exports.decimalAdjust =(type, value, exp) ->
  #If the exp is undefined or zero...
  if typeof exp == 'undefined' || +exp == 0
    return Math[type](value)
  value = +value
  exp = +exp
  #If the value is not a number or the exp is not an integer...
  if isNaN(value) || !(typeof exp == 'number' && exp % 1 == 0)
    return NaN
  #Shift
  value = value.toString().split('e')
  v = if value[1] then (+value[1] - exp) else -exp
  value = Math[type](+(value[0] + 'e' + v))
  #Shift back
  value = value.toString().split('e')
  v = if value[1] then (+value[1] + exp) else exp
  +(value[0] + 'e' + v )