C#
possui o decimal
tipo usado para números que precisam de representação exata na base 10. Por exemplo, 0.1
não pode ser representado na base 2 (por exemplo, float
e double
) e sempre será uma aproximação quando armazenado em variáveis desses tipos.
Fiquei me perguntando se o fato inverso também era possível. Existem números que não são representáveis na base 10, mas podem ser representados na base 2 (nesse caso, eu gostaria de usar um em float
vez de um decimal
para lidar com eles)?
c#
numbers
floating-point
Máx.
fonte
fonte
0.11_b2
, escreva-o como0.5 + 0.5 * 0.5
. Existe alguma etapa que possa falhar ou resultar em um decimal repetido? Pessoalmente, acho que esse exercício faz um ótimo trabalho ao transmitir uma intuição sobre os números da base 2. Suponho que alguém poderia dar um passo adiante e transformar esse exercício em uma prova de construção.0.0999999....998..
exatamente, mas não o número completo0.1
- aproximações como arredondar para as centenas mais próximas0.100
são uma preocupação de implementação que envolve não mostrar todos os dígitos e arredondá-los.Respostas:
Aqui está a chave para o seu dilema:
10
é o produto de2
e5
. Você pode representar qualquer número exatamente na base de 10 casas decimais que é k * 1/2 n * 1/5 m , ondek
,n
em
são inteiros.Alternativamente fraseado - se o número
n
em 1 / N contém um factor que não faz parte dos elementos da base, o número não serão capazes de ser representados exactamente em um número fixo de dígitos do binário / decimal / qualquer que seja a expansão desse número - terá uma parte repetida. Por exemplo 1/15 = 0,0666666666 .... porque 3 (15 = 3 * 5) não é um fator de 10.Assim, qualquer coisa que possa ser representada exatamente na base 2 (k * 1/2 n ) pode ser representada exatamente na base 10.
Além disso, há a questão de quantos dígitos / bits você está usando para representar o número. Existem alguns números que podem ser representados exatamente em alguma base, mas são necessários mais do que algum número de dígitos / bits.
Em binário, o número 1/10 que é convenientemente 0,1 em decimal não pode ser representado como um número que pode ser representado em um número fixo de bits em binário. Em vez disso, o número é 0.00011001100110011 ... 2 (com a parte 0011 repetindo para sempre).
Vamos olhar para o número 1 2 /1010 2 um pouco mais de perto.
Este é exatamente o mesmo tipo de coisa que você obtém ao tentar fazer a divisão longa por 1/3.
1/10, quando fatorado é 1 / (2 1 * 5 1 ). Para a base 10 (ou qualquer múltiplo de 10), esse número termina e é conhecido como número regular . Uma expansão decimal que se repete é conhecida como decimal de repetição , e os números que duram para sempre sem repetir são números irracionais.
A matemática por trás dessa investiga o pequeno teorema de Fermat ... e uma vez que você começar a dizer Fermat ou teorema, torna-se uma questão Math.SE .
A resposta é não'.
Portanto, neste ponto, devemos esclarecer que toda expansão binária de comprimento fixo de um número racional pode ser representada como uma expansão decimal de comprimento fixo.
Vamos olhar mais de perto o decimal em C #, que nos leva ao ponto flutuante decimal no .NET e, dado o autor, aceito que é assim que funciona.
Vou apontar imediatamente que, por causa dessa implementação, existem números do
double
tipo que não podem ser representadosdecimal
- aqueles que estão fora do intervalo.Double.Epsilon
é4.94065645841247e-324
que não pode ser representado em umdecimal
, mas pode em umdouble
.No entanto, dentro do intervalo que o decimal pode representar, ele tem mais bits de precisão do que outros tipos nativos e pode representá-los sem erros.
Existem outros tipos flutuando. Há um BigInteger em C # que pode representar um número inteiro arbitrariamente grande. Não há equivalente ao BigDecimal do Java (que pode representar números com dígitos decimais de até 2 32 dígitos - o que é um intervalo considerável) exatamente . No entanto, se você bisbilhotar um pouco, poderá encontrar implementações feitas à mão.
Existem algumas linguagens que também têm um tipo de dados racional que permite representar exatamente os racionais (de modo que 1/3 é na verdade 1/3).
Especificamente para C # e para a escolha de float ou racional, passarei a Jon Skeet da caneca flutuante Decimal no .NET :
fonte
n = 15
eb = 10
não são relativamente primos ("não compartilham fatores positivos comuns (divisores), exceto 1")) porque compartilham 5 como um fator. A chave é que nem todos os fatores de 15 (5 e 3) também não são 10. (Além disso: existe uma palavra para indicar números que compartilham ou não todos os fatores comuns?). embrulhado em suak, n, m
equação, mas para realmente envolvê-lo, eu precisaria ver um gráfico em 3D. Independentemente, bem merecido +1 para você.Depois de sair do intervalo de valores aceitáveis, a resposta é sim. Dito isto, quase tudo dentro do intervalo terá uma representação. Referência decimal em C # Embora não declarado na especificação, os números irracionais não podem ser representados exatamente (por exemplo, e 1 , pi, raiz quadrada de 2 etc.).
1 Obrigado a MichaelT por me lembrar de outro número irracional.
fonte
e
(2,71 ...). O logon natural - ln (x) é a base de logs e. Assim, bases irracionais existem e são úteis. A utilidade particular da base pi, não tenho certeza - mas isso não significa que não seja usada em algum lugar.Um tipo de ponto flutuante de base dois seria capaz de representar com precisão muitos valores que um tipo de base dez do mesmo tamanho não poderia. Qualquer valor que seria exatamente representável por um tipo de base 2 de algum tamanho seria exatamente representável em um tipo de base 10 de tamanho suficiente. O tamanho exigido para um tipo puramente de base dez para representar todos os valores de um número de ponto flutuante binário dependeria do intervalo de expoente do tipo binário; centenas de bits para a
float
ou milhares para adouble
.Dito isto, o
Decimal
tipo é grande o suficiente para tornar possível o uso como um tipo "universal" capaz de manter o valor de qualquer outra primitiva numérica e fornecer outros recursos adicionais além disso (se nada mais, use um bit para indicar se o valor armazenado é o resultado da conversão de adouble
e, se esse bit estiver definido, use 64 bits para manter o valor em questão). A Microsoft optou por não fazer isso, no entanto. Como resultado, a conversão dedouble
aDecimal
falhará completamente para valores grandes, fará com que valores pequenos sejam arredondados para o 1E-28 mais próximo. Além disso, mesmo dentro da faixa dinâmica dedecimal
, o método de conversão não será "ida e volta". Por exemplo, avaliar 1,0 / 3,0 como duplo produzirá 0,333333333333333314148, mas a conversão para decimal produzirá 0,33333333333333333m e a conversão de volta para duplo resultará em 0,33333333333333323218.fonte