Floydian Posted October 23, 2008 Share Posted October 23, 2008 So, I was talking to someone about the problems with using large numbers and I though, hmmm, why not write a script that does basic math the way a person does. We can (hopefully :P ) do addition, multiplication, subtraction, and division with 100% precision to an extent far far greater than PHP math does (if we had enough time, I'd say our precision is infinite). Well, I've made an addition module and a multiplication module. Feel free to try out the code, and if you think it will be useful to you, you may use it. You may modify the code, you can sell it, you can do whatever you want with it. <?php set_time_limit(0); class precisionMath { function add($v1,$v2) { $p1 = strpos($v1, '.'); $p2 = strpos($v2, '.'); if ($p1 !== false) { $x1 = substr($v1, $p1 + 1); $v1 = substr($v1, 0, $p1); } else { $x1 = 0; } if ($p2 !== false) { $x2 = substr($v2, $p2 + 1); $v2 = substr($v2, 0, $p2); } else { $x2 = 0; } if ($x1 or $x2) { $x1 = str_split($x1); $x2 = str_split($x2); $xc1 = count($x1); $xc2 = count($x2); if ($xc1 >= $xc2) { for ($x = 1; $x <= $xc1 - $xc2; $x++) { $x2[] = '0'; } $bd = $x1; $cd = $x2; } else { for ($x = 1; $x <= $xc2 - $xc1; $x++) { $x1[] = '0'; } $bd = $x2; $cd = $x1; } $bd = array_reverse($bd); $cd = array_reverse($cd); $last = ''; foreach ($bd as $key => $value) { if (!isset($cd[$key])) { break; } else { $bd[$key] += $cd[$key]; if ($bd[$key] >= 10) { $bd[$key] -= 10; if (isset($bd[$key + 1])) { $bd[$key + 1]++; } else { $last = 1; } } } } } // End of decimal portion. $v1 = str_split($v1); $v2 = str_split($v2); if (count($v1) >= count($v2)) { $b = $v1; $c = $v2; } else { $b = $v2; $c = $v1; } $b = array_reverse($b); $c = array_reverse($c); if (isset($last) and $last == 1) { $b[0]++; } $last = ''; foreach ($b as $key => $value) { if (!isset($c[$key])) { break; } else { $b[$key] += $c[$key]; if ($b[$key] >= 10) { $b[$key] -= 10; if (isset($b[$key + 1])) { $b[$key + 1]++; } else { $last = 1; } } } } if (isset($bd)) { return $last . implode(array_reverse($b)) . '.' . implode(array_reverse($bd)); } else { return $last . implode(array_reverse($b)); } } function mult($v1,$v2) { $p1 = strpos($v1, '.'); $p2 = strpos($v2, '.'); $v1_len = strlen($v1); $v2_len = strlen($v2); if ($p1 !== false) { $p1 = $v1_len - $p1 - 1; $v1_len--; $v1 = str_replace('.', '', $v1); } else { $p1 = 0; } if ($p2 !== false) { $p2 = $v2_len - $p2 - 1; $v2_len--; $v2 = str_replace('.', '', $v2); } else { $p2 = 0; } if (strlen($v1) >= strlen($v2)) { $b = $v1; $c = $v2; } else { $b = $v2; $c = $v1; } $c = array_reverse(str_split($c)); $sum = '0'; foreach ($c as $key => $value) { $subtotal = '0'; for ($x = 1; $x <= $value; $x++) { $subtotal = $this->add($subtotal, $b); } $padding = str_repeat('0', $key); $subtotal .= $padding; $sum = $this->add($sum, $subtotal); } if ($p1 or $p2) { $sum_len = strlen($sum); $p = $this->add($p1, $p2); $start = substr($sum, 0, $sum_len - $p); $end = substr($sum, $sum_len - $p); $sum = $start . '.' . $end; } return $sum; } } $math = new precisionMath(); $r1 = $math->add('1324751973451345817344593459173457139457934759455714395719345719745917450', '13451749571934751982375172351743571349571935471947591734591734571439571947597459184'); $r2 = $math->add('9874514.1435162451345790234759017345917345971394571934759173459714395719345791475901745', '7830947513454.1834534875074938579304579347698273469723496720937560927569275627681034858345803485'); $r3 = $math->mult('1324751973451345817344593459173457139457934759455714395719345719745917450', '13451749571934751982375172351743571349571935471947591734591734571439571947597459184'); $r4 = $math->mult('9874514.1435162451345790234759017345917345971394571934759173459714395719345791475901745', '7830947513454.1834534875074938579304579347698273469723496720937560927569275627681034858345803485'); echo <<<EOT Addition with no decimals: $r1 Addition with decimals: $r2 Multiplication with no decimals: $r3 Multiplication with decimals: $r4 EOT; Quote Link to comment Share on other sites More sharing options...
Floydian Posted October 24, 2008 Author Share Posted October 24, 2008 Re: Human Math Update The previous example did not accept negative numbers. The new one accepts negative numbers in the addition and multiplication methods. I've also added in a subtraction module, and it also accepts negative numbers. All three modules accept decimal numbers and negative numbers, or any combination of those. <?php set_time_limit(0); class precisionMath { function isNegative($value) { if (strpos($value, '-') === 0) { return true; } else { return false; } } function stripNegative($value) { return substr($value, 1); } function add($v1,$v2) { if ($this->isNegative($v1)) { $v1 = $this->stripNegative($v1); $v1_neg = true; } else { $v1_neg = false; } if ($this->isNegative($v2)) { $v2 = $this->stripNegative($v2); $v2_neg = true; } else { $v2_neg = false; } if (!$v1_neg and !$v2_neg) { return $this->addMechanics($v1,$v2); } elseif($v1_neg and !$v2_neg) { if ($v1 == $v2) { return 0; } elseif ($v1 > $v2) { $result = $this->minus_mechanics($v1, $v2); return '-' . $result; } else { return $this->minus_mechanics($v2, $v1); } } elseif(!$v1_neg and $v2_neg) { if ($v1 == $v2) { return 0; } elseif ($v1 > $v2) { return $this->minus_mechanics($v1, $v2); } else { $result = $this->minus_mechanics($v2, $v1); return '-' . $result; } } else { return '-' . $this->addMechanics($v1,$v2); } } function addMechanics($v1,$v2) { $p1 = strpos($v1, '.'); $p2 = strpos($v2, '.'); if ($p1 !== false) { $x1 = substr($v1, $p1 + 1); $v1 = substr($v1, 0, $p1); } else { $x1 = 0; } if ($p2 !== false) { $x2 = substr($v2, $p2 + 1); $v2 = substr($v2, 0, $p2); } else { $x2 = 0; } if ($x1 or $x2) { $x1 = str_split($x1); $x2 = str_split($x2); $xc1 = count($x1); $xc2 = count($x2); if ($xc1 >= $xc2) { for ($x = 1; $x <= $xc1 - $xc2; $x++) { $x2[] = '0'; } $bd = $x1; $cd = $x2; } else { for ($x = 1; $x <= $xc2 - $xc1; $x++) { $x1[] = '0'; } $bd = $x2; $cd = $x1; } $bd = array_reverse($bd); $cd = array_reverse($cd); $last = ''; foreach ($bd as $key => $value) { if (!isset($cd[$key])) { break; } else { $bd[$key] += $cd[$key]; if ($bd[$key] >= 10) { $bd[$key] -= 10; if (isset($bd[$key + 1])) { $bd[$key + 1]++; } else { $last = 1; } } } } } // End of decimal portion. $v1 = str_split($v1); $v2 = str_split($v2); if (count($v1) >= count($v2)) { $b = $v1; $c = $v2; } else { $b = $v2; $c = $v1; } $b = array_reverse($b); $c = array_reverse($c); if (isset($last) and $last == 1) { $b[0]++; } $last = ''; foreach ($b as $key => $value) { if (!isset($c[$key])) { break; } else { $b[$key] += $c[$key]; if ($b[$key] >= 10) { $b[$key] -= 10; if (isset($b[$key + 1])) { $b[$key + 1]++; } else { $last = 1; } } } } if (isset($bd)) { return $last . implode(array_reverse($b)) . '.' . implode(array_reverse($bd)); } else { return $last . implode(array_reverse($b)); } } function minus($v1,$v2) { if ($this->isNegative($v1)) { $v1 = $this->stripNegative($v1); $v1_neg = true; } else { $v1_neg = false; } if ($this->isNegative($v2)) { $v2 = $this->stripNegative($v2); $v2_neg = true; } else { $v2_neg = false; } if (!$v1_neg and !$v2_neg and $v1 >= $v2) { return $this->minus_mechanics($v1,$v2); } elseif (!$v1_neg and !$v2_neg and $v1 < $v2) { return '-' . $this->minus_mechanics($v2,$v1); } elseif($v1_neg and !$v2_neg) { return '-' . $this->addMechanics($v1, $v2); } elseif(!$v1_neg and $v2_neg) { return $this->addMechanics($v1, $v2); } else { if ($v1 >= $v2) { return '-' . $this->minus_mechanics($v1,$v2); } else { return $this->minus_mechanics($v2,$v1); } } } function minus_mechanics($b,$c) { $p1 = strpos($b, '.'); $p2 = strpos($c, '.'); if ($p1 !== false) { $bd = substr($b, $p1 + 1); $b = substr($b, 0, $p1); } else { $bd = 0; } if ($p2 !== false) { $cd = substr($c, $p2 + 1); $c = substr($c, 0, $p2); } else { $cd = 0; } if ($bd or $cd) { $bd = str_split($bd); $cd = str_split($cd); $xc1 = count($bd); $xc2 = count($cd); if ($xc1 >= $xc2) { for ($x = 1; $x <= $xc1 - $xc2; $x++) { $cd[] = '0'; } } else { for ($x = 1; $x <= $xc2 - $xc1; $x++) { $bd[] = '0'; } } $bd = array_reverse($bd); $cd = array_reverse($cd); $last = ''; foreach ($bd as $key => $value) { // echo '<pre>' . print_r($bd, 1) . '</pre> '; if (!isset($cd[$key])) { break; } else { $bd[$key] -= $cd[$key]; if ($bd[$key]< 0) { $bd[$key] += 10; if (isset($bd[$key + 1])) { $bd[$key + 1]--; } else { $last = 1; } } } } } // End of decimal portion. $b = str_split($b); $c = str_split($c); $b = array_reverse($b); $c = array_reverse($c); if (isset($last) and $last == 1) { $b[0]--; } $last = ''; foreach ($b as $key => $value) { if (!isset($c[$key])) { break; } else { if ($b[$key] < $c[$key]) { $temp_key = $key; do { if (!isset($b[$temp_key + 1])) { $temp_key = false; } elseif ($b[$temp_key + 1] == 0) { $b[$temp_key + 1] = 9; $temp_key++; } else { $b[$temp_key + 1]--; $temp_key = false; $b[$key] += 10; } } while ($temp_key); } $b[$key] = $b[$key] - $c[$key]; // $b[$key] = abs($b[$key] - $c[$key]); } } $b = implode(array_reverse($b)); do { $length = strlen($b); if ($length == 1) { $zeros = false; } else { $zeros = substr($b, 0, 1); if ($zeros == 0) { $b = substr($b, 1); } } } while ($zeros === '0'); if (isset($bd)) { return $b . '.' . implode(array_reverse($bd)); } else { return $b; } } function mult($v1, $v2) { if ($this->isNegative($v1)) { $v1 = $this->stripNegative($v1); $v1_neg = true; } else { $v1_neg = false; } if ($this->isNegative($v2)) { $v2 = $this->stripNegative($v2); $v2_neg = true; } else { $v2_neg = false; } $result = $this->mult_mechanics($v1, $v2); if (!$v1_neg and !$v2_neg or $v1_neg and $v2_neg) { return $result; } else { return '-' . $result; } } function mult_mechanics($v1,$v2) { $p1 = strpos($v1, '.'); $p2 = strpos($v2, '.'); $v1_len = strlen($v1); $v2_len = strlen($v2); if ($p1 !== false) { $p1 = $v1_len - $p1 - 1; $v1_len--; $v1 = str_replace('.', '', $v1); } else { $p1 = 0; } if ($p2 !== false) { $p2 = $v2_len - $p2 - 1; $v2_len--; $v2 = str_replace('.', '', $v2); } else { $p2 = 0; } if (strlen($v1) >= strlen($v2)) { $b = $v1; $c = $v2; } else { $b = $v2; $c = $v1; } $c = array_reverse(str_split($c)); $sum = '0'; foreach ($c as $key => $value) { $subtotal = '0'; for ($x = 1; $x <= $value; $x++) { $subtotal = $this->addMechanics($subtotal, $b); } $padding = str_repeat('0', $key); $subtotal .= $padding; $sum = $this->addMechanics($sum, $subtotal); } if ($p1 or $p2) { $sum_len = strlen($sum); $p = $this->addMechanics($p1, $p2); $start = substr($sum, 0, $sum_len - $p); $end = substr($sum, $sum_len - $p); $sum = $start . '.' . $end; } return $sum; } } $math = new precisionMath(); $r1 = $math->add('1324751973451345817344593459173457139457934759455714395719345719745917450', '13451749571934751982375172351743571349571935471947591734591734571439571947597459184'); $r2 = $math->add('9874514.1435162451345790234759017345917345971394571934759173459714395719345791475901745', '7830947513454.1834534875074938579304579347698273469723496720937560927569275627681034858345803485'); $r3 = $math->minus_mechanics('1245735846732546254625472753451346234626526243523451345134623462346234623462643357325472546256257254723255257352', '12457358467325462546254727535732547254625625725472275257256'); $r4 = $math->minus_mechanics('1245735846732546254625472753451346234626526243523451345134623462346234623462643357325472546256257254723255257352.1124362546245724572434523456256254625462456254362562562565732457', '12457358467325462546254727535732547254625625725472275257256.94775234523423462543625462546245623456234562345624562456254625623456254625462546245624566246256256'); $r5 = $math->mult('1324751973451345817344593459173457139457934759455714395719345719745917450', '13451749571934751982375172351743571349571935471947591734591734571439571947597459184'); $r6 = $math->mult('9874514.1435162451345790234759017345917345971394571934759173459714395719345791475901745', '7830947513454.1834534875074938579304579347698273469723496720937560927569275627681034858345803485'); echo <<<EOT Addition with no decimals: $r1 Addition with decimals: $r2 Subtraction with no decimals: $r3 Subtraction with decimals: $r4 Multiplication with no decimals: $r5 Multiplication with decimals: $r6 EOT; Quote Link to comment Share on other sites More sharing options...
Hash-Op Posted October 28, 2008 Share Posted October 28, 2008 Re: Human Math Sweet work Floydian. Very well constructed. Thanks Quote Link to comment Share on other sites More sharing options...
Karlos Posted October 28, 2008 Share Posted October 28, 2008 Re: Human Math Nice One Quote Link to comment Share on other sites More sharing options...
Floydian Posted October 28, 2008 Author Share Posted October 28, 2008 Re: Human Math You're welcome ;) And thanks for the good words! Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.