Como você pode arredondar qualquer número (não apenas inteiros> 0) para N dígitos significativos?
Por exemplo, se eu quiser arredondar para três dígitos significativos, estou procurando uma fórmula que possa ter:
1.239.451 e retorno 1.240.000
12,1257 e retorno 12,1
0,0681 e retorno 0,0681
5 e retorno 5
Naturalmente, o algoritmo não deve ser codificado para lidar apenas com N de 3, embora isso fosse um começo.
Respostas:
Aqui está o mesmo código em Java sem o bug 12.100000000000001 que outras respostas têm
Também removi o código repetido, mudei
power
para um tipo inteiro para evitar problemas de flutuação quandon - d
terminar e tornei o intermediário longo mais claroO bug foi causado pela multiplicação de um grande número por um pequeno número. Em vez disso, divido dois números de tamanho semelhante.
EDIT
Corrigido mais bugs. Adicionada verificação de 0, pois resultaria em NaN. Fez a função funcionar realmente com números negativos (o código original não lida com números negativos porque um log de um número negativo é um número complexo)
fonte
Aqui está uma implementação de JavaScript curta e agradável:
fonte
n==0
:)Math.log(n) / Math.LN10
vez deMath.log10(n)
?Math.floor(x) == Math.ceil(x) - 1
? Porque não faz quandox
é um inteiro. Acho que o segundo argumento dapow
função deveria sersig - Math.ceil(Math.log(n) / Math.LN10)
(ou apenas usarMath.log10
)RESUMO:
Portanto, você precisa encontrar a casa decimal do primeiro dígito diferente de zero, salvar os próximos N-1 dígitos e arredondar o enésimo dígito com base no resto.
Podemos usar o log para fazer o primeiro.
Portanto, para números> 0, calcule o teto do log. Para números <0, tome o chão do log.
Agora temos o dígito
d
: 7 no primeiro caso, 2 no segundo, -2 no terceiro.Temos que arredondar o
(d-N)
décimo dígito. Algo como:Em seguida, faça o arredondamento padrão:
E desfaça o pow.
Onde a potência é a potência calculada acima.
Sobre a precisão: a resposta da pirólise está de fato mais próxima do resultado real. Mas observe que você não pode representar 12,1 exatamente em qualquer caso. Se você imprimir as respostas da seguinte forma:
As respostas são:
Então, use a resposta do Pyro!
fonte
Não é a implementação "curta e agradável" de JavaScript
por exemplo
?
Desculpe, não estou sendo jocoso aqui, é só que usar a função "roundit" de Claudiu e .toPrecision em JavaScript me dá resultados diferentes, mas apenas no arredondamento do último dígito.
JavaScript:
.INTERNET
fonte
Number(814301).toPrecision(4) == "8.143e+5"
. Geralmente não é o que você deseja se estiver mostrando aos usuários.A solução pirolística (muito boa!) Ainda tem um problema. O valor duplo máximo em Java é da ordem de 10 ^ 308, enquanto o valor mínimo é da ordem de 10 ^ -324. Portanto, você pode ter problemas ao aplicar a função
roundToSignificantFigures
a algo que está dentro de algumas potências de dez deDouble.MIN_VALUE
. Por exemplo, quando você ligaentão a variável
power
terá o valor 3 - (-309) = 312. Consequentemente, a variávelmagnitude
se tornaráInfinity
, e é tudo lixo a partir de então. Felizmente, esse não é um problema intransponível: é apenas o fatormagnitude
que está transbordando. O que importa mesmo é o produtonum * magnitude
, e isso não transborda. Uma maneira de resolver isso é dividir a multiplicação pelo fatormagintude
em duas etapas:fonte
Que tal esta solução java:
fonte
Aqui está uma versão modificada do JavaScript de Ates que lida com números negativos.
fonte
Isso veio 5 anos atrasado, mas vou compartilhar com outras pessoas que ainda têm o mesmo problema. Eu gosto porque é simples e sem cálculos no lado do código. Consulte Métodos integrados para exibição de figuras significativas para obter mais informações.
Isso se você quiser apenas imprimi-lo.
Se você quiser convertê-lo:
Aqui está um exemplo disso em ação:
fonte
JavaScript:
A
Number
função mudará a saída do formulário"8.143e+5"
para"814300"
.fonte
Você já tentou codificá-lo da maneira como faria à mão?
fonte
[Corrigido, 26/10/2009]
Essencialmente, para N dígitos fracionários significativos :
• Multiplique o número por 10 N
• Some 0,5
• Trunque os dígitos da fração (ou seja, trunque o resultado em um inteiro)
• Divida por 10 N
Para N dígitos integrais significativos (não fracionários):
• Divida o número por 10 N
• Some 0,5
• Trunque os dígitos da fração (ou seja, trunque o resultado em um inteiro)
• Multiplique por 10 N
Você pode fazer isso em qualquer calculadora, por exemplo, que tenha um operador "INT" (truncamento de inteiro).
fonte
fonte
Aqui está o código da Pirolística (atualmente a melhor resposta) em Visual Basic.NET, caso alguém precise:
fonte
Este é um que eu criei em VB:
fonte
return new BigDecimal(value, new MathContext(significantFigures, RoundingMode.HALF_UP)).doubleValue();
fonte
Eu precisava disso no Go, o que era um pouco complicado pela falta de biblioteca padrão do Go
math.Round()
(antes do go1.10). Então eu tive que agitar isso também. Aqui está a minha tradução da excelente resposta da Pirolística :fonte
Você pode evitar fazer todos esses cálculos com potências de 10 etc. usando apenas FloatToStrF.
FloatToStrF permite que você (entre outras coisas) escolha a precisão (número de algarismos significativos) no valor de saída (que será uma string). Claro, você poderia então aplicar StrToFloat a isso para obter seu valor arredondado como um float.
Veja aqui:
http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/SysUtils_FloatToStrF@Extended@TFloatFormat@[email protected]
fonte
Este código usa a função de formatação embutida que é transformada em uma função de arredondamento
fonte