24 self::ENGLISH => array(
29 self::METRIC => array(
'pt',
'0.352777778',
'mm'),
31 self::METRIC => array(
34 self::ENGLISH => array(
'mm',
'2.83464567',
'pt'),
53 public function __construct($output_precision = 4, $internal_precision = 10, $force_no_bcmath =
false) {
54 $this->outputPrecision = $output_precision;
55 $this->internalPrecision = $internal_precision;
56 $this->bcmath = !$force_no_bcmath && function_exists(
'bcmul');
77 public function convert($length, $to_unit) {
79 if (!$length->isValid())
return false;
82 $unit = $length->getUnit();
84 if ($n ===
'0' || $unit ===
false) {
88 $state = $dest_state =
false;
89 foreach (self::$units as $k =>
$x) {
90 if (isset(
$x[$unit])) $state = $k;
91 if (isset(
$x[$to_unit])) $dest_state = $k;
93 if (!$state || !$dest_state)
return false;
104 $log = (int) floor(log(abs($n), 10));
105 $cp = (
$log < 0) ? $this->internalPrecision -
$log : $this->internalPrecision;
107 for ($i = 0; $i < 2; $i++) {
110 if ($dest_state === $state) {
112 $dest_unit = $to_unit;
115 $dest_unit = self::$units[$state][$dest_state][0];
119 if ($dest_unit !== $unit) {
120 $factor = $this->
div(self::$units[$state][$unit], self::$units[$state][$dest_unit], $cp);
121 $n = $this->
mul($n, $factor, $cp);
133 if ($dest_state === $state) {
146 $n = $this->
mul($n, self::$units[$state][$dest_state][1], $cp);
147 $unit = self::$units[$state][$dest_state][2];
148 $state = $dest_state;
155 if ($unit !== $to_unit)
return false;
161 $n = $this->
round($n, $sigfigs);
162 if (strpos($n,
'.') !==
false) $n = rtrim($n,
'0');
174 $n = ltrim($n,
'0+-');
175 $dp = strpos($n,
'.');
177 $sigfigs = strlen(rtrim($n,
'0'));
179 $sigfigs = strlen(ltrim($n,
'0.'));
180 if ($dp !== 0) $sigfigs--;
188 private function add($s1, $s2, $scale) {
189 if ($this->bcmath)
return bcadd($s1, $s2, $scale);
190 else return $this->
scale($s1 + $s2, $scale);
196 private function mul($s1, $s2, $scale) {
197 if ($this->bcmath)
return bcmul($s1, $s2, $scale);
198 else return $this->
scale($s1 * $s2, $scale);
204 private function div($s1, $s2, $scale) {
205 if ($this->bcmath)
return bcdiv($s1, $s2, $scale);
206 else return $this->
scale($s1 / $s2, $scale);
213 private function round($n, $sigfigs) {
214 $new_log = (int) floor(log(abs($n), 10));
215 $rp = $sigfigs - $new_log - 1;
216 $neg = $n < 0 ?
'-' :
'';
219 $n = bcadd($n, $neg .
'0.' . str_repeat(
'0', $rp) .
'5', $rp + 1);
220 $n = bcdiv($n,
'1', $rp);
224 $n = bcadd($n, $neg .
'5' . str_repeat(
'0', $new_log - $sigfigs), 0);
225 $n = substr($n, 0, $sigfigs + strlen($neg)) . str_repeat(
'0', $new_log - $sigfigs + 1);
229 return $this->
scale(
round($n, $sigfigs - $new_log - 1), $rp + 1);
236 private function scale($r, $scale) {
240 $r = sprintf(
'%.0f', (
float) $r);
245 $precise = (string)
round(substr($r, 0, strlen($r) + $scale), -1);
247 return substr($precise, 0, -1) . str_repeat(
'0', -$scale + 1);
249 return sprintf(
'%.' . $scale .
'f', (
float) $r);