Jump to content
MakeWebGames

Human Math


Floydian
 Share

Recommended Posts

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;
Link to comment
Share on other sites

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;

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...