Tenho vários métodos para acumular quantidades em números de precisão fixa com base no seguinte tipo de dados:
int95_t {
long long int x;
int y;
};
Os números são contados para frente x
até que possam ficar fora dos limites e retornar, momento em que y
acumulam +1 para estouro e -1 para subfluxo. (Eu também tenho métodos para adicionar números de ponto flutuante, o que pode causar vários estouros ou subfluxos de x
e, portanto, acumular várias vezes em y
).
Os métodos para adicionar ou subtrair neste tipo de dados são um tanto complexos.
int95_t sum(const int95_t a, const int95_t b) {
int95_t result = { a.x + b.x, a.y + b.y };
result.y += (1 - (2 * (b.x < 0LL))) * ((a.x ^ result.x) < 0 && (a.x ^ b.x) >= 0LL) * 2;
return result;
}
int95_t subtract(const int95_t a, const int95_t b) {
const int95_t neg_b = { -b.x, -b.y + (2 * (b.x == LLONG_MIN)) };
return sum(a, neg_b);
}
Sobrecarreguei os operadores +
, -
, +=
, e -=
para esse tipo de dado, mas isso não ajuda a limpar meu código tanto assim e pelo seguinte motivo: em muitos contextos, armazenarei não uma matriz de int95_t
valores, mas duas matrizes separadas de valores long long int
e int
. (O motivo é que há muitas condições sob as quais o acumulador supernário y
pode ser ignorado com segurança, e eu quero conservar a largura de banda da memória.) Assim, tenho muitas situações em que, para adicionar um int95_t a outro nessas circunstâncias, parece que ainda preciso fazer:
long long int primary[8];
int secondary[8];
int95_t add_this = { 81573835283, 3816 };
for (int i = 0; i < 8; i++) {
int95_t tmp = { primary[i], secondary[i] };
tmp += add_this;
primary[i] = tmp.x;
secondary[i] = tmp.y;
}
Existe alguma maneira melhor? Eu esperaria poder contar com qualquer compilador C++ para interpretar corretamente algo assim no caso acima, mas não tenho certeza:
for (int i = 0; i < 8; i++) {
{ primary[i], secondary[i] } += add_this;
}
Obrigado por qualquer ajuda que vocês possam oferecer.
Uma das soluções poderia ser criar um objeto temporário com aritmética sobrecarregada que contenha referências a componentes operandos. Por exemplo:
Você também pode reutilizar esta classe para
int95_t
implementação de operadores sobrecarregados, ou seja