|
<?php |
|
|
|
function calculateMaxScale(string $leftOperandStart = '0.1', string $rightOperandStart = '0.1') : void |
|
{ |
|
if (\preg_replace('/[^0-1\.]/', '', $leftOperandStart) !== $leftOperandStart) { |
|
throw new \Exception('left operand must contain "0", ".", and "1"'); |
|
} elseif (\preg_replace('/[^0-1\.]/', '', $rightOperandStart) !== $rightOperandStart) { |
|
throw new \Exception('right operand must contain "0", ".", and "1"'); |
|
} elseif ($leftOperandStart[0] !== '0' || $leftOperandStart[1] !== '.') { |
|
throw new \Exception(\sprintf('left operand must start with "0.", "%s" supplied', $leftOperandStart)); |
|
} elseif ($rightOperandStart[0] !== '0' || $rightOperandStart[1] !== '.') { |
|
throw new \Exception(\sprintf('right operand must start with "0.", "%s" supplied', $rightOperandStart)); |
|
} elseif (\substr_count($leftOperandStart, '.') !== 1) { |
|
throw new \Exception('left operand must only one and only one decimal point character'); |
|
} elseif (\substr_count($rightOperandStart, '.') !== 1) { |
|
throw new \Exception('right operand must only one and only one decimal point character'); |
|
} |
|
|
|
$leftOperand = $leftOperandIncrement = $leftOperandStart; |
|
$rightOperand = $rightOperandIncrement = $rightOperandStart; |
|
|
|
$leftOperandWhole = \explode('.', $leftOperand); |
|
$leftOperandWhole = $leftOperandWhole[1]; |
|
$leftOperandIterations = \str_pad('1', \strlen($leftOperandWhole) + 1, '0', STR_PAD_RIGHT); |
|
|
|
$rightOperandWhole = \explode('.', $rightOperand); |
|
$rightOperandWhole = $rightOperandWhole[1]; |
|
$rightOperandIterations = \str_pad('1', \strlen($rightOperandWhole) + 1, '0', STR_PAD_RIGHT); |
|
|
|
$iterations = 0; |
|
$maxScale = 0; |
|
|
|
$expected = \strlen($leftOperandWhole) + \strlen($rightOperandWhole); |
|
|
|
// We would have to have a calculation that yields 1000 zeros beyond our |
|
// "expected" max scale, THEN non-zero values afterwards, for this |
|
// method to yield a false result. |
|
$maxSupport = $expected + 1000; |
|
|
|
do { |
|
$iterations++; |
|
$innerIterations = 0; |
|
|
|
do { |
|
$innerIterations++; |
|
|
|
$value = \bcmul($leftOperand, $rightOperand, $maxSupport); |
|
$value = \rtrim($value, '0'); |
|
|
|
$scale = \explode('.', $value); |
|
$scale = $scale[1]; |
|
$scale = \strlen($scale); |
|
|
|
$value = \rtrim($value, '.'); |
|
|
|
if ($scale > $maxScale) { |
|
$maxScale = $scale; |
|
} |
|
|
|
echo \sprintf( |
|
"\tExpected: %s\tMax Scale: %s\tLeft Operand: %s\tRight Operand: %s\tScale: %s\tValue: %s\n", |
|
$expected, $maxScale, $leftOperand, $rightOperand, $scale, $value |
|
); |
|
|
|
if ($expected < $maxScale) { |
|
throw new \Exception (\sprintf( |
|
'ERROR! Theory proven wrong. Expected max scale "%s". Actual max scale "%s" for last operation.', |
|
$expected, |
|
$maxScale |
|
)); |
|
} |
|
|
|
$rightOperand = \bcadd($rightOperand, $rightOperandIncrement, \strlen($rightOperandWhole)); |
|
|
|
} while ($innerIterations < $rightOperandIterations); |
|
|
|
$leftOperand = \bcadd($leftOperand, $leftOperandIncrement, \strlen($leftOperandWhole)); |
|
$rightOperand = $rightOperandStart; |
|
|
|
} while ($iterations < $leftOperandIterations); |
|
} |
|
|
|
$exampleTests = [ |
|
['0.1', '0.1'], |
|
['0.1', '0.01'], |
|
['0.1', '0.001'], |
|
['0.1', '0.0001'], |
|
['0.1', '0.00001'], |
|
['0.1', '0.000001'], |
|
['0.1', '0.0000001'], |
|
['0.1', '0.00000001'], |
|
['0.1', '0.000000001'], |
|
['0.1', '0.0000000001'], |
|
['0.01', '0.1'], |
|
['0.01', '0.01'], |
|
['0.01', '0.001'], |
|
['0.01', '0.0001'], |
|
['0.01', '0.00001'], |
|
['0.01', '0.000001'], |
|
['0.01', '0.0000001'], |
|
['0.01', '0.00000001'], |
|
['0.01', '0.000000001'], |
|
['0.01', '0.0000000001'], |
|
['0.001', '0.1'], |
|
['0.001', '0.01'], |
|
['0.001', '0.001'], |
|
['0.001', '0.0001'], |
|
['0.001', '0.00001'], |
|
['0.001', '0.000001'], |
|
['0.001', '0.0000001'], |
|
['0.001', '0.00000001'], |
|
['0.001', '0.000000001'], |
|
['0.001', '0.0000000001'], |
|
['0.0001', '0.1'], |
|
['0.0001', '0.01'], |
|
['0.0001', '0.001'], |
|
['0.0001', '0.0001'], |
|
['0.0001', '0.00001'], |
|
['0.0001', '0.000001'], |
|
['0.0001', '0.0000001'], |
|
['0.0001', '0.00000001'], |
|
['0.0001', '0.000000001'], |
|
['0.0001', '0.0000000001'], |
|
['0.00001', '0.1'], |
|
['0.00001', '0.01'], |
|
['0.00001', '0.001'], |
|
['0.00001', '0.0001'], |
|
['0.00001', '0.00001'], |
|
['0.00001', '0.000001'], |
|
['0.00001', '0.0000001'], |
|
['0.00001', '0.00000001'], |
|
['0.00001', '0.000000001'], |
|
['0.00001', '0.0000000001'], |
|
['0.000001', '0.1'], |
|
['0.000001', '0.01'], |
|
['0.000001', '0.001'], |
|
['0.000001', '0.0001'], |
|
['0.000001', '0.00001'], |
|
['0.000001', '0.000001'], |
|
['0.000001', '0.0000001'], |
|
['0.000001', '0.00000001'], |
|
['0.000001', '0.000000001'], |
|
['0.000001', '0.0000000001'], |
|
['0.0000001', '0.1'], |
|
['0.0000001', '0.01'], |
|
['0.0000001', '0.001'], |
|
['0.0000001', '0.0001'], |
|
['0.0000001', '0.00001'], |
|
['0.0000001', '0.000001'], |
|
['0.0000001', '0.0000001'], |
|
['0.0000001', '0.00000001'], |
|
['0.0000001', '0.000000001'], |
|
['0.0000001', '0.0000000001'], |
|
['0.00000001', '0.1'], |
|
['0.00000001', '0.01'], |
|
['0.00000001', '0.001'], |
|
['0.00000001', '0.0001'], |
|
['0.00000001', '0.00001'], |
|
['0.00000001', '0.000001'], |
|
['0.00000001', '0.0000001'], |
|
['0.00000001', '0.00000001'], |
|
['0.00000001', '0.000000001'], |
|
['0.00000001', '0.0000000001'], |
|
['0.000000001', '0.1'], |
|
['0.000000001', '0.01'], |
|
['0.000000001', '0.001'], |
|
['0.000000001', '0.0001'], |
|
['0.000000001', '0.00001'], |
|
['0.000000001', '0.000001'], |
|
['0.000000001', '0.0000001'], |
|
['0.000000001', '0.00000001'], |
|
['0.000000001', '0.000000001'], |
|
['0.000000001', '0.0000000001'], |
|
['0.0000000001', '0.1'], |
|
['0.0000000001', '0.01'], |
|
['0.0000000001', '0.001'], |
|
['0.0000000001', '0.0001'], |
|
['0.0000000001', '0.00001'], |
|
['0.0000000001', '0.000001'], |
|
['0.0000000001', '0.0000001'], |
|
['0.0000000001', '0.00000001'], |
|
['0.0000000001', '0.000000001'], |
|
['0.0000000001', '0.0000000001'], |
|
]; |
|
|
|
foreach ($exampleTests as $test) { |
|
\calculateMaxScale($test[0], $test[1]); |
|
} |