/** * Set a new type, and convert the value * * @param string $type New type to set * @throws Zend\Measure\Exception * @return Zend\Measure\AbstractMeasure */ public function setType($type) { if (empty($this->_units[$type])) { throw new Exception("Type ($type) is unknown"); } if (empty($this->_type)) { $this->_type = $type; } else { // Convert to standard value $value = $this->_value; if (is_array($this->_units[$this->getType()][0])) { foreach ($this->_units[$this->getType()][0] as $key => $found) { switch ($key) { case "/": if ($found != 0) { $value = call_user_func(Math::$div, $value, $found, 25); } break; case "+": $value = call_user_func(Math::$add, $value, $found, 25); break; case "-": $value = call_user_func(Math::$sub, $value, $found, 25); break; default: $value = call_user_func(Math::$mul, $value, $found, 25); break; } } } else { $value = call_user_func(Math::$mul, $value, $this->_units[$this->getType()][0], 25); } // Convert to expected value if (is_array($this->_units[$type][0])) { foreach (array_reverse($this->_units[$type][0]) as $key => $found) { switch ($key) { case "/": $value = call_user_func(Math::$mul, $value, $found, 25); break; case "+": $value = call_user_func(Math::$sub, $value, $found, 25); break; case "-": $value = call_user_func(Math::$add, $value, $found, 25); break; default: if ($found != 0) { $value = call_user_func(Math::$div, $value, $found, 25); } break; } } } else { $value = call_user_func(Math::$div, $value, $this->_units[$type][0], 25); } $slength = strlen($value); $length = 0; for($i = 1; $i <= $slength; ++$i) { if ($value[$slength - $i] != '0') { $length = 26 - $i; break; } } $this->_value = Math::round($value, $length); $this->_type = $type; } return $this; }
public function testNegativeRounding() { $this->assertEquals( '-3', Math::round('-3.4')); $this->assertEquals( round(-3.4), Math::round('-3.4')); $this->assertEquals( '-4', Math::round('-3.5')); $this->assertEquals( round(-3.5), Math::round('-3.5')); $this->assertEquals( '-4', Math::round('-3.6')); $this->assertEquals( round(-3.6), Math::round('-3.6')); $this->assertEquals( '-4', Math::round('-3.6', 0)); $this->assertEquals( round(-3.6,0), Math::round('-3.6', 0)); $this->assertEquals( '-1.96', Math::round('-1.95583', 2), '', 0.02); $this->assertEquals( round(-1.95583,2), Math::round('-1.95583', 2), '', 0.02); $this->assertEquals( -1242000, Math::round('-1241757', -3), '', 250); $this->assertEquals(round(-1241757, -3), Math::round('-1241757', -3), '', 250); $this->assertEquals( -5.05, Math::round('-5.045', 2), '', 0.02); $this->assertEquals( round(-5.045, 2), Math::round('-5.045', 2), '', 0.02); $this->assertEquals( -5.06, Math::round('-5.055', 2), '', 0.02); $this->assertEquals( round(-5.055, 2), Math::round('-5.055', 2), '', 0.02); }
/** * Rounds a number to its last significant figure * * @param integer|float|string $value the number to round * @return float the rounded number */ protected function roundToPrecision($value) { $slength = strlen($value); $length = 0; for ($i = 1; $i <= $slength; ++$i) { if ($value[$slength - $i] != '0') { $length = 26 - $i; break; } } return Math::round($value, $length); }
/** * Returns a locale formatted number depending on the given options. * The seperation and fraction sign is used from the set locale. * ##0.# -> 12345.12345 -> 12345.12345 * ##0.00 -> 12345.12345 -> 12345.12 * ##,##0.00 -> 12345.12345 -> 12,345.12 * * @param string $input Localized number string * @param array $options Options: number_format, locale, precision. See {@link setOptions()} for details. * @throws \Zend\Locale\Exception\InvalidArgumentException * @return string locale formatted number */ public static function toNumber($value, array $options = array()) { $value = Math::normalize($value); $value = Math::floatalize($value); $options = self::_checkOptions($options) + self::$_options; $options['locale'] = (string) $options['locale']; // Get correct signs for this locale $symbols = Cldr::getList($options['locale'], 'symbols'); $oenc = iconv_get_encoding('internal_encoding'); iconv_set_encoding('internal_encoding', 'UTF-8'); // Get format $format = $options['number_format']; if ($format === null) { $format = Cldr::getContent($options['locale'], 'decimalnumber'); $format = self::_seperateFormat($format, $value, $options['precision']); if ($options['precision'] !== null) { $value = Math::normalize(Math::round($value, $options['precision'])); } } else { // seperate negative format pattern when available $format = self::_seperateFormat($format, $value, $options['precision']); if (strpos($format, '.')) { if (is_numeric($options['precision'])) { $value = Math::round($value, $options['precision']); } else { if (substr($format, iconv_strpos($format, '.') + 1, 3) == '###') { $options['precision'] = null; } else { $options['precision'] = iconv_strlen(iconv_substr($format, iconv_strpos($format, '.') + 1, iconv_strrpos($format, '0') - iconv_strpos($format, '.'))); $format = iconv_substr($format, 0, iconv_strpos($format, '.') + 1) . '###' . iconv_substr($format, iconv_strrpos($format, '0') + 1); } } } else { $value = Math::round($value, 0); $options['precision'] = 0; } $value = Math::normalize($value); } if (iconv_strpos($format, '0') === false) { iconv_set_encoding('internal_encoding', $oenc); throw new Exception\InvalidArgumentException('Wrong format... missing 0'); } // get number parts $pos = iconv_strpos($value, '.'); if ($pos !== false) { if ($options['precision'] === null) { $precstr = iconv_substr($value, $pos + 1); } else { $precstr = iconv_substr($value, $pos + 1, $options['precision']); if (iconv_strlen($precstr) < $options['precision']) { $precstr = $precstr . str_pad("0", $options['precision'] - iconv_strlen($precstr), "0"); } } } else { if ($options['precision'] > 0) { $precstr = str_pad("0", $options['precision'], "0"); } } if ($options['precision'] === null) { if (isset($precstr)) { $options['precision'] = iconv_strlen($precstr); } else { $options['precision'] = 0; } } // get fraction and format lengths if (strpos($value, '.') !== false) { $number = substr((string) $value, 0, strpos($value, '.')); } else { $number = $value; } $prec = call_user_func(Math::$sub, $value, $number, $options['precision']); $prec = Math::floatalize($prec); $prec = Math::normalize($prec); if (iconv_strpos($prec, '-') !== false) { $prec = iconv_substr($prec, 1); } if ($prec == 0 and $options['precision'] > 0) { $prec = "0.0"; } if ($options['precision'] + 2 > iconv_strlen($prec)) { $prec = str_pad((string) $prec, $options['precision'] + 2, "0", STR_PAD_RIGHT); } if (iconv_strpos($number, '-') !== false) { $number = iconv_substr($number, 1); } $group = iconv_strrpos($format, ','); $group2 = iconv_strpos($format, ','); $point = iconv_strpos($format, '0'); // Add fraction $rest = ""; if (iconv_strpos($format, '.')) { $rest = iconv_substr($format, iconv_strpos($format, '.') + 1); $length = iconv_strlen($rest); for ($x = 0; $x < $length; ++$x) { if ($rest[0] == '0' || $rest[0] == '#') { $rest = iconv_substr($rest, 1); } } $format = iconv_substr($format, 0, iconv_strlen($format) - iconv_strlen($rest)); } if ($options['precision'] == '0') { if (iconv_strrpos($format, '-') != 0) { $format = iconv_substr($format, 0, $point) . iconv_substr($format, iconv_strrpos($format, '#') + 2); } else { $format = iconv_substr($format, 0, $point); } } else { $format = iconv_substr($format, 0, $point) . $symbols['decimal'] . iconv_substr($prec, 2); } $format .= $rest; // Add seperation if ($group == 0) { // no seperation $format = $number . iconv_substr($format, $point); } else { if ($group == $group2) { // only 1 seperation $seperation = $point - $group; for ($x = iconv_strlen($number); $x > $seperation; $x -= $seperation) { if (iconv_substr($number, 0, $x - $seperation) !== "") { $number = iconv_substr($number, 0, $x - $seperation) . $symbols['group'] . iconv_substr($number, $x - $seperation); } } $format = iconv_substr($format, 0, iconv_strpos($format, '#')) . $number . iconv_substr($format, $point); } else { // 2 seperations if (iconv_strlen($number) > $point - $group) { $seperation = $point - $group; $number = iconv_substr($number, 0, iconv_strlen($number) - $seperation) . $symbols['group'] . iconv_substr($number, iconv_strlen($number) - $seperation); if (iconv_strlen($number) - 1 > $point - $group + 1) { $seperation2 = $group - $group2 - 1; for ($x = iconv_strlen($number) - $seperation2 - 2; $x > $seperation2; $x -= $seperation2) { $number = iconv_substr($number, 0, $x - $seperation2) . $symbols['group'] . iconv_substr($number, $x - $seperation2); } } } $format = iconv_substr($format, 0, iconv_strpos($format, '#')) . $number . iconv_substr($format, $point); } } // set negative sign if (call_user_func(Math::$comp, $value, 0, $options['precision']) < 0) { if (iconv_strpos($format, '-') === false) { $format = $symbols['minus'] . $format; } else { $format = str_replace('-', $symbols['minus'], $format); } } iconv_set_encoding('internal_encoding', $oenc); return (string) $format; }