private function addStrings($number1, $number2, $fractional = false)
    {
        // optimization - numbers can be treated as integers as long as they don't overflow the max int size
        if ('0' !== $number1[0]
            && '0' !== $number2[0]
            && strlen($number1) <= $this->maxSafeIntStringSize
            && strlen($number2) <= $this->maxSafeIntStringSize
        ) {
            return (string) ((int) $number1 + (int) $number2);
        }

        // find out which of the strings is longest
        $maxLength = max(strlen($number1), strlen($number2));

        // add leading or trailing zeroes as needed
        $number1 = str_pad($number1, $maxLength, '0', $fractional ? STR_PAD_RIGHT : STR_PAD_LEFT);
        $number2 = str_pad($number2, $maxLength, '0', $fractional ? STR_PAD_RIGHT : STR_PAD_LEFT);

        $result = '';
        $carryOver = 0;
        for ($i = $maxLength - 1; 0 <= $i; $i--) {
            $sum = $number1[$i] + $number2[$i] + $carryOver;

            $result .= $sum % 10;
            $carryOver = (int) ($sum >= 10);
        }
        if ($carryOver > 0) {
            $result .= '1';
        }

        return strrev($result);
    }