JavaScript Python PHP
function executar(operation = 'X% de Y', first = '10', second = '200', adjustment = 'Aumento') {
const PERCENTAGE_OPERATIONS = ['X% de Y', 'A representa quantos % de B', 'Variação percentual', 'Aplicar aumento ou desconto'];
function parse(input, label) {
const text = input.trim();
if (text.length > 30 || !/^[+-]?\d{1,15}(?:[.,]\d{1,12})?$/.test(text))
throw new Error(`${label}: informe um decimal válido, com até 15 dígitos inteiros e 12 casas; sem agrupamento, expoentes ou separadores misturados.`);
const [integer, decimal = ''] = text.replace(',', '.').split('.');
const sign = integer.startsWith('-') ? -BigInt(1) : BigInt(1);
return { n: sign * BigInt(integer.replace(/^[+-]/, '') + decimal), d: BigInt(10) ** BigInt(decimal.length) };
}
const multiply = (a, b) => ({ n: a.n * b.n, d: a.d * b.d });
const subtract = (a, b) => ({ n: a.n * b.d - b.n * a.d, d: a.d * b.d });
function divide(a, b) {
if (b.n === BigInt(0))
throw new Error('Divisão por zero: o denominador deve ser diferente de zero.');
return { n: a.n * b.d * (b.n < BigInt(0) ? -BigInt(1) : BigInt(1)), d: a.d * (b.n < BigInt(0) ? -b.n : b.n) };
}
function display(label, fraction, percent = false) {
const negative = fraction.n < BigInt(0);
const magnitude = (negative ? -fraction.n : fraction.n) * BigInt(1000000);
let rounded = magnitude / fraction.d;
const remainder = magnitude % fraction.d;
if (remainder * BigInt(2) >= fraction.d)
rounded++;
const decimals = String(rounded % BigInt(1000000)).padStart(6, '0').replace(/0+$/, '');
const value = `${negative && rounded !== BigInt(0) ? '-' : ''}${rounded / BigInt(1000000)}${decimals ? ',' + decimals : ''}${percent ? '%' : ''}`;
return { label, value, approximate: remainder !== BigInt(0) };
}
function calculatePercentage(operation, first, second, adjustment = 'Aumento') {
if (!PERCENTAGE_OPERATIONS.some(value => value === operation))
throw new Error('Selecione uma operação válida.');
const labels = operation === PERCENTAGE_OPERATIONS[0] ? ['X (taxa)', 'Y (valor)'] : operation === PERCENTAGE_OPERATIONS[1] ? ['A', 'B'] : operation === PERCENTAGE_OPERATIONS[2] ? ['Valor inicial', 'Valor final'] : ['Valor base', 'Taxa'];
const a = parse(first, labels[0]);
const b = parse(second, labels[1]);
const hundred = { n: BigInt(100), d: BigInt(1) };
if (operation === PERCENTAGE_OPERATIONS[0])
return { formula: 'Y × X / 100', values: [display('Resultado', divide(multiply(b, a), hundred))] };
if (operation === PERCENTAGE_OPERATIONS[1])
return { formula: 'A / B × 100', values: [display('Percentual', multiply(divide(a, b), hundred), true)] };
if (operation === PERCENTAGE_OPERATIONS[2]) {
if (a.n <= BigInt(0) || b.n < BigInt(0))
throw new Error('Variação exige valor inicial positivo e valor final não negativo.');
return { formula: '(final − inicial) / inicial × 100', values: [display('Variação percentual', multiply(divide(subtract(b, a), a), hundred), true)] };
}
if (!['Aumento', 'Desconto'].includes(adjustment))
throw new Error('Selecione Aumento ou Desconto.');
if (a.n < BigInt(0))
throw new Error('O valor base do aumento/desconto deve ser não negativo.');
if (b.n < BigInt(0) || (adjustment === 'Desconto' && b.n > hundred.n * b.d))
throw new Error('A taxa deve ser não negativa; descontos são limitados a 100%.');
const change = divide(multiply(a, b), hundred);
const total = subtract(a, { ...change, n: adjustment === 'Aumento' ? -change.n : change.n });
return { formula: `alteração = base × taxa / 100; total = base ${adjustment === 'Aumento' ? '+' : '−'} alteração`, values: [display(`Valor do ${adjustment.toLowerCase()}`, change), display('Total', total)] };
}
return calculatePercentage(operation, first, second, adjustment);
}
import re
from fractions import Fraction
def executar(operation="X% de Y", first="10", second="200", adjustment="Aumento"):
def parse(text):
text = text.strip()
if len(text) > 30 or not re.fullmatch(r"[+-]?[0-9]{1,15}(?:[.,][0-9]{1,12})?", text):
raise ValueError("Use até 15 dígitos inteiros e 12 casas, sem agrupamento ou expoentes.")
return Fraction(text.replace(",", "."))
operations = ("X% de Y", "A representa quantos % de B", "Variação percentual", "Aplicar aumento ou desconto")
if operation not in operations:
raise ValueError("Selecione uma operação válida.")
a, b = parse(first), parse(second)
def display(label, value, percent=False):
scaled = abs(value) * 1000000
number, remainder = divmod(scaled.numerator, scaled.denominator)
number += 2 * remainder >= scaled.denominator
integer, decimal = divmod(number, 1000000)
digits = str(decimal).zfill(6).rstrip("0")
text = ("-" if value < 0 and number else "") + str(integer) + ("," + digits if digits else "") + ("%" if percent else "")
return {"label":label, "value":text, "approximate":remainder != 0}
if operation == operations[0]:
return {"formula":"Y × X / 100", "values":[display("Resultado", b * a / 100)]}
if operation == operations[1]:
if b == 0: raise ValueError("Divisão por zero: o denominador deve ser diferente de zero.")
return {"formula":"A / B × 100", "values":[display("Percentual", a / b * 100, True)]}
if operation == operations[2]:
if a <= 0 or b < 0: raise ValueError("Variação exige inicial positivo e final não negativo.")
return {"formula":"(final − inicial) / inicial × 100", "values":[display("Variação percentual", (b - a) / a * 100, True)]}
if adjustment not in ("Aumento", "Desconto") or a < 0 or b < 0 or (adjustment == "Desconto" and b > 100):
raise ValueError("Base e taxa não negativas; descontos limitados a 100%.")
change = a * b / 100
total = a + change if adjustment == "Aumento" else a - change
return {"formula":f"alteração = base × taxa / 100; total = base {'+' if adjustment == 'Aumento' else '−'} alteração", "values":[display("Valor do " + adjustment.lower(), change), display("Total", total)]}
<?php
use Brick\Math\BigRational;
use Brick\Math\RoundingMode;
require_once 'vendor/autoload.php';
function executar($operation = 'X% de Y', $first = '10', $second = '200', $adjustment = 'Aumento') {
$parse = function ($text) {
$text = trim($text);
if (strlen($text) > 30 || !preg_match('/^[+-]?[0-9]{1,15}(?:[.,][0-9]{1,12})?$/D', $text)) throw new InvalidArgumentException('Use até 15 dígitos inteiros e 12 casas, sem agrupamento ou expoentes.');
return BigRational::of(str_replace(',', '.', ltrim($text, '+')));
};
$operations = ['X% de Y', 'A representa quantos % de B', 'Variação percentual', 'Aplicar aumento ou desconto'];
if (!in_array($operation, $operations, true)) throw new InvalidArgumentException('Operação inválida.');
$a = $parse($first); $b = $parse($second);
$display = function ($label, $fraction, $percent = false) {
$rounded = $fraction->toScale(6, RoundingMode::HALF_UP);
$value = rtrim(rtrim((string)$rounded, '0'), '.');
return ['label'=>$label, 'value'=>str_replace('.', ',', $value).($percent ? '%' : ''), 'approximate'=>$fraction->compareTo($rounded) !== 0];
};
if ($operation === $operations[0]) return ['formula'=>'Y × X / 100', 'values'=>[$display('Resultado', $b->multipliedBy($a)->dividedBy(100))]];
if ($operation === $operations[1]) {
if ($b->isZero()) throw new InvalidArgumentException('Divisão por zero.');
return ['formula'=>'A / B × 100', 'values'=>[$display('Percentual', $a->dividedBy($b)->multipliedBy(100), true)]];
}
if ($operation === $operations[2]) {
if ($a->compareTo(0) <= 0 || $b->isNegative()) throw new InvalidArgumentException('Inicial positivo e final não negativo são obrigatórios.');
return ['formula'=>'(final − inicial) / inicial × 100', 'values'=>[$display('Variação percentual', $b->minus($a)->dividedBy($a)->multipliedBy(100), true)]];
}
if (!in_array($adjustment, ['Aumento', 'Desconto'], true) || $a->isNegative() || $b->isNegative() || ($adjustment === 'Desconto' && $b->compareTo(100) > 0)) throw new InvalidArgumentException('Base e taxa não negativas; descontos até 100%.');
$change = $a->multipliedBy($b)->dividedBy(100);
$total = $adjustment === 'Aumento' ? $a->plus($change) : $a->minus($change);
return ['formula'=>'alteração = base × taxa / 100; total = base '.($adjustment === 'Aumento' ? '+' : '−').' alteração', 'values'=>[$display('Valor do '.strtolower($adjustment), $change), $display('Total', $total)]];
}