O centavo fantasma
Quem já executou um cronograma plurianual da ASC 606 no Excel, em um ERP como o NetSuite Advanced Revenue Management (ARM) ou o Workday, ou em um script próprio já viu isso: um contrato de $1,000,000.00 em 36 meses reconhece $1,000,000.08 ou $999,999.72, dependendo de cada mês ser arredondado para cima ou para baixo.
Alguns centavos não são uma distorção. São um incômodo com custo:
- O cronograma não fecha com o valor do contrato.
- O saldo diferido nunca chega a zero, então alguém lança um ajuste de ponta.
- Cada ajuste é um item de conciliação a explicar ao revisor e ao auditor.
- Ajustes manuais recorrentes levantam perguntas sobre os controles em torno do cronograma.
O que o ponto flutuante faz, e o que não faz?
A maioria dos softwares armazena números em ponto flutuante binário, e frações decimais como 0.10 não têm forma binária exata. Esse erro de representação é da ordem de uma parte em 10^16, pequeno demais para alterar um valor arredondado para o centavo. Os centavos vêm do arredondamento de cada período isoladamente:
// Rounding each month to the cent
const contractTotal = 100000.00;
const periods = 36;
const monthly = contractTotal / periods; // 2777.777...
let sum = 0;
for (let i = 0; i < 36; i++) {
sum += Number(monthly.toFixed(2)); // 2777.78 every month
}
console.log(sum.toFixed(2)); // "100000.08": eight cents over
A aritmética decimal dá os mesmos oito centavos. A solução é uma regra para o resto, e não apenas um tipo numérico diferente.
Como o arredondamento se acumula em contratos com múltiplos elementos?
Tome um contrato com:
- Assinatura da plataforma ($120,000 em 12 meses)
- Serviços de implementação ($35,000, baseados em marcos)
- Suporte premium ($15,000 em 12 meses)
- Upsell no meio do prazo ($25,000, proporcional)
A alocação por SSP relativo divide o preço da transação pela participação de cada obrigação: alocação à obrigação i = preço da transação × SSP de i ÷ soma de todos os SSPs. Se cada alocação for arredondada isoladamente para o centavo antes do cronograma, as alocações já podem diferir do preço da transação em um centavo, antes de o primeiro mês ser lançado. Depois, cada cronograma divide novamente. O guia do centavo residual percorre um exemplo com três obrigações.
Aritmética de inteiros com regra de resto
O Soluqube calcula em aritmética de inteiros (BigInt) na escala 10^6, arredondada para centavos, com absorção do resto no último período:
- Valores inteiros: os valores são multiplicados por 1,000,000 e calculados apenas com aritmética de inteiros (
BigIntdo JavaScript). - Guarde o resto: para qualquer divisão P / N, guarde o quociente Q e o resto R, de modo que P = N × Q + R.
- Atribua o resto: o último período de cada obrigação absorve R.
// Amounts in cents; the final period absorbs the remainder
export function buildSchedule(totalCents: bigint, periods: bigint): bigint[] {
const base = totalCents / periods;
const remainder = totalCents % periods;
const schedule: bigint[] = [];
for (let i = 0n; i < periods; i++) {
schedule.push(i === periods - 1n ? base + remainder : base);
}
return schedule; // sums to totalCents exactly
}
Teste outros valores e prazos de contrato no simulador de cronogramas.
O que muda na auditoria?
- Cronogramas que fecham: as alocações e todos os períodos somam o preço da transação, e cada obrigação termina com saldo diferido de $0.00.
- Menos ajustes a explicar: sem ajustes de arredondamento de fim de mês nesses contratos.
- Resultado reexecutável: as mesmas entradas dão os mesmos centavos, e a exportação traz hashes SHA-256 com uma raiz de Merkle para que o revisor possa confirmar que ela não foi alterada.
Os centavos são a parte fácil; os auditores gastam seu tempo no SSP por trás da alocação. Para uma visão sistema a sistema, veja NetSuite ARM vs Soluqube e o hub ASC 606, ou traga três contratos para o programa de parceiros de design (design partner).