Saturday 22 July 2017

C float mantissa binary options


Eu tenho um programa, que está sendo executado em dois processadores, um dos quais não tem suporte a ponto flutuante. Então, eu preciso executar cálculos de ponto flutuante usando ponto fixo nesse processador. Para esse efeito, eu estarei usando uma biblioteca de emulação de ponto flutuante. Eu preciso primeiro extrair os sinais, mantissas e expoentes de números de ponto flutuante no processador que suportam ponto flutuante. Então, a minha pergunta é como posso obter o sinal, mantissa e expoente de um único número de ponto flutuante de precisão. Seguindo o formato desta figura, Isso é o que eu fiz até agora, mas exceto sinal, nem mantissa e expoente estão corretos. Eu acho, estou faltando alguma coisa. Pediu Mar 28 13 às 15:00 I39m assumindo IEEE 754 binário de 32 bits. Você está ciente dos seguintes problemas (1) O expoente é induzido, adicionando 127 ao expoente real. (2) Todas as flutuações, exceto as muito pequenas, são normalizadas eo primeiro bit de uma mantissa flutuante normalizada não é armazenado. Ndash Patricia Shanahan Mar 28 13 em 17:05 There39s nenhuma lei que diz que você tem que usar apenas as coisas para o que eles foram originalmente criados para. Caso contrário, o primeiro avião não usaria pedaços de bicicleta. QuotGenerallyquot undefined Que sobre aquelas ocasiões em que é definido, ou quando you39re feliz com o comportamento em uma dada plataforma / situação ndash Alex Feb 28 14 at 11:29 Alex Existe realmente uma lei que diz que você só pode fazer algumas coisas e não outros Em C. Ele chamou o quotISO / IEC 9899: 2011 especificação, coloquialmente conhecido como o quotC linguagem standardquot. E se isso lhe diz que o que você está fazendo é indefinido que significa que você pode obter qualquer coisa de volta. Um dia poderia funcionar, o próximo poderia dar-lhe o resultado errado e ainda no dia seguinte poderia simplesmente falhar. Isso é o quotundefinedquot significa. Ndash Voo 24 feb às 19:08 Este método falha quando 1) float não é IEEE 754 32 bit binário (não tão raro) 2) unsigned é de 16 bits (comum no mundo incorporado) 3) endian de unsigned47float não correspondem. (raro). 4) A interpretação matemática é usada para o exponente 47mantissa como esta resposta mostra o expoente polarizado eo significand / mantissa incompleto. Ndash chux Mar 5 at 17:34 Descubra o formato dos números de ponto flutuante usados ​​na CPU que suporta diretamente ponto flutuante e quebrá-lo para baixo nessas partes. O formato mais comum é IEEE-754. Alternativamente, você poderia obter essas partes usando algumas funções especiais (duplo frexp (valor duplo, int exp) e duplo ldexp (double x, int exp)) como mostrado nesta resposta. Meu conselho é manter a regra 0 e não refazer o que as bibliotecas padrão já fazem, se isso é suficiente. Olhe para math. h (cmath no padrão C) e funções frexp, frexpf, frexpl, que quebram um valor de ponto flutuante (double, float, ou duplo longo) em sua parte significand e expoente. Para extrair o sinal do significand você pode usar signbit, também em math. h / cmath, ou copysign (apenas C11). Algumas alternativas, com menor semântica, são modf e ilogb / scalbn, disponível em C11 en. cppreference / w / cpp / numeric / math / logb compara-los, mas eu não encontrei na documentação como todas essas funções se comportam com / - inf E NaNs. Finalmente, se você realmente quiser usar bitmasks (por exemplo, você precisa desesperadamente saber os bits exatos, e seu programa pode ter diferentes NaNs com diferentes representações, e você não confia nas funções acima), pelo menos tornar tudo independente da plataforma usando o Macros em float. h / cfloat. Respondeu Oct 26 13 at 16:12 Você está ampliando os bits errados. Eu acho que você quer: Lembre-se, quando você amp. Você está zerando bits que você não definir. Então, neste caso, você quer zerar o bit de sinal quando você recebe o expoente, e você quer zerar o bit de sinal eo expoente quando você começa a mantissa. Observe que as máscaras vêm diretamente de sua imagem. Assim, a máscara de expoente será parecido com: 0 11111111 00000000000000000000000 ea máscara de mantissa será semelhante a: 0 00000000 11111111111111111111111 respondeu Mar 28 13 at 15:07 Eu ainda don39t obter resultados corretos. Ndash MetallicPriest Mar 28 13 às 15:10 MetallicPriest Tente agora, eu tinha as máscaras erradas pela primeira vez. Ndash Xymostech Mar 28 13 at 15:12 O que sobre o chamado bit escondido eu don39t ver alguém configurá-lo: m 0x00800000. Observe que o número deve ser verificado para valores especiais (denormals, NaN, infinities) em primeiro lugar, uma vez que estes exigem tratamento diferente. Ndash Rudy Velthuis Mar 29 13 às 22: 16Parte Flutuante Thomas Finley, Abril de 2000 Conteúdo e Introdução Este documento explica o padrão IEEE 754 de ponto flutuante. Ele explica a representação binária desses números, como converter para decimal de ponto flutuante, como converter de ponto flutuante para decimal, discute casos especiais em ponto flutuante e, finalmente, termina com algum código C para outros entendimento de ponto flutuante. Este documento não abrange operações com números de ponto flutuante. Eu escrevi este documento para que, se você sabe como representar, você pode ignorar a seção de representação, e se você sabe como converter para decimal de precisão única, você pode ignorar essa seção, e se você sabe como converter para precisão única de Decimal, você pode pular essa seção. Representação Primeiro, saiba que os números binários podem ter, se você perdoar o meu dizendo assim, um ponto decimal. Ele funciona mais ou menos da mesma maneira que o ponto decimal faz com números decimais. Por exemplo, o decimal 22.589 é apenas 22 e 510-1 810 -2 910 -3. Similarmente, o número binário 101.001 é simplesmente 12 2 02 1 12 0 02 -1 02 -2 12 -3. Ou melhor, simplesmente 2 2 2 0 2 -3 (este número específico funciona para ser 9.125, se isso ajuda o seu pensamento). Segundo, saiba que números binários, como números decimais, podem ser representados em notação científica. Por exemplo. O decimal 923.52 pode ser representado como 9.2352 10 2. Da mesma forma, números binários podem ser expressos dessa forma também. Digamos que temos o número binário 101011.101 (que é 43.625). Isso seria representado usando notação científica como 1,01011101 2 5. Agora que tenho certeza de que a compreensão é perfeita, posso finalmente entrar em representação. A unidade de ponto flutuante de precisão simples é um pacote de 32 bits, dividido em três seções um bit, oito bits e vinte e três bits, nessa ordem. Eu vou fazer uso do número binário mencionado anteriormente 1.01011101 2 5 para ilustrar como um tomaria um número binário em notação científica e representá-lo em notação de ponto flutuante. Se convertemos simplesmente de hex para binário, 0x64 é 0110 0100, que é o mesmo resultado que o 011001 produzido acima. Este método é muito mais rápido. De qualquer forma Pegamos os números que temos e os representamos como .011001, colocando-os na ordem em que os adquirimos. Colocado em sequência com a nossa representação binária de 329, obtemos 101001001.011001. Em nossa notação científica binária, isto é 1.01001001011001 2 8. Então usamos o que sabemos sobre como números de precisão simples são representados para completar este processo. O sinal é positivo, então o campo do sinal é 0. O expoente é 8. 8 127 135, então o campo do expoente é 10000111. A mantissa é meramente 01001001011001 (lembre-se o implícito 1 da mantissa significa que não incluímos o líder 1) mais Entretanto muitos 0s nós temos que adicionar ao lado direito para fazer esse número binário 23 bocados por muito tempo. Uma vez que um dos problemas de lição de casa envolve representar isso como hex, eu vou terminar com um número hexadecimal. Em seguida, quebra-lo em pedaços de quatro bits (já que cada dígito hexadecimal é o equivalente a 4 bits) e, em seguida, converter cada quantidade de quatro bits no dígito hexadecimal correspondente. Assim, em hexadecimal, este número é 0x43A4B200. Números especiais Às vezes, o computador sente a necessidade de apresentar um resultado de um cálculo que reflete que algum erro foi feito. Talvez a magnitude do resultado de um cálculo fosse maior ou menor do que esse formato pareceria ser capaz de suportar. Talvez você tenha tentado dividir por zero. A resposta é que há casos especiais de números de ponto flutuante, especificamente quando o campo de expoente é todo 1 bits (255) ou todos os 0 bits (0). Números desnormalizados Se você tem um campo de expoente que é todos os bits zero, isso é o que é chamado um número desnormalizado. Com o campo do expoente igual a zero, você pensaria que o expoente real seria -127, então este número tomaria a forma de 1.MANTISSA 2 -127 como descrito acima, mas não. Em vez disso, é 0.MANTISSA 2 -126. Observe que o expoente não é mais o valor do campo exponencial menos 127. É simplesmente -126. Observe também que não incluímos mais um bit implícito para a mantissa. Como exemplo, pegue o número de ponto flutuante representado como 0x80280000. Primeiro, converta isso para binário. Nosso bit de sinal é 1, então esse número é negativo. Nosso expoente é 0, então sabemos que este é um número desnormalizado. Nossa mantissa é 0101, o que reflete uma mantissa real de 0,0101 lembre-se de que não incluímos o que era anteriormente um bit implícito para um expoente de zero. Assim, isto significa que temos um número -0,0101 2 2 -126 -0,3125 10 2 -126 -1,25 10 2 -128. Zero Você pode pensar em zero como simplesmente um outro número desnormalizado. Zero é representado por um expoente de zero e uma mantissa de zero. A partir de nossa compreensão dos números desnormalizados, isto se traduz em 02 -126 0. Este bit de sinal pode ser positivo (0) ou negativo (1), levando a um zero positivo ou negativo. Isso não faz muito sentido matematicamente, mas é permitido. Infinito Assim como o caso de todos os bits zero no campo do expoente é um caso especial, assim é o caso de todos os bits. Se o campo do expoente é todos os, ea mantissa é todos os zeros, então este número é um infinito. Pode haver infinitos positivos ou negativos dependendo do bit de sinal. Por exemplo, 0x7F800000 é infinito positivo e 0xFF800000 é infinito negativo. NaN (Not a Number) Essas quantidades especiais têm um campo de expoente de 255 (todos os bits) como o infinito, mas diferem da representação do infinito em que a mantissa contém alguns bits. Não importa onde estão ou quantos deles há, apenas contanto que existam alguns. O bit de sinal parece não ter nenhuma influência nisso. Exemplos desta quantidade especial incluem 0x7FFFFFFF, 0xFF81ABD0, 0x7FAA12F9 e soforth. Resumo de Casos Especiais Um resumo de casos especiais é mostrado na tabela abaixo. É mais ou menos uma cópia da tabela encontrada na página 301 da segunda edição da Computer Organization and Design, a Interface de Software de Hardware por Patterson e Hennessy, o livro didático para Ciência da Computação 104 no semestre da Primavera de 2000. Mesmo que apenas a precisão única tenha sido abordada no texto acima, eu incluo a dupla precisão por razões de completude. Quando, Onde e Onde Não Quando você tem operações como 0/0 ou subtraindo o infinito do infinito (ou alguma outra computação ambígua), você receberá NaN. Quando você divide um número por zero, você terá um infinito. No entanto, a contabilização dessas operações especiais exige algum esforço extra por parte do projetista e pode levar a operações mais lentas, já que mais transistores são utilizados no design de chips. Por esse motivo, às vezes, as CPUs não contabilizam essas operações e, em vez disso, geram uma exceção. Por exemplo, quando eu tento dividir por zero ou fazer operações com infinito, meu computador gera exceções e se recusa a concluir a operação (meu computador tem um processador G3 ou MPC750). Helper Software Se você estiver interessado em investigar mais, eu incluo dois programas para os quais eu fornecer o código C que você pode executar para obter uma maior compreensão de como funciona flutuante e também para verificar o seu trabalho em várias atribuições. Hex 2 Float Este programa aceita como entrada uma quantidade hexadecimal e lê-lo como dados brutos na variável theFloat. Em seguida, o programa emite a representação hexadecimal dos dados no Float (repetindo a entrada) e imprime ao lado dela a quantidade de ponto flutuante que representa. Mostro aqui uma amostra do programa. Observe as quantidades de ponto flutuante de casos especiais (0, infinito e não um número). Para os números desnormalizados mas não nulos, este programa exibirá zero mesmo que o número não seja realmente zero. Se você quiser contornar esse problema, substitua o f na seqüência de formatação da função printf com e, que desativará o número com grande precisão com notação científica. Eu não o tive como e porque eu encontro a notação científica extremamente irritante. Float 2 Hex Esta é uma ligeira modificação do programa Hex 2 Float. A exceção é que ele lê em um número de ponto flutuante. Assim como e saídas a forma hexadecimal mais o número de ponto flutuante. Novamente, eu incluo um exemplo de execução deste programa, confirmando os resultados dos exemplos de problemas que abordamos anteriormente neste texto, juntamente com alguns outros casos simples. Observe a representação hexadecimal de 0,2. E esse é o fim desse capítulo. Thomas Finley 2000Você pode baixar este artigo como um arquivo Word97 ou RTF. Este artigo se aplica a todas as versões do Microsoft Excel para Windows. Este artigo foi escrito por Chip Pearson, 27-Oct-1998. Copyright, 1998, 1999, Charles H. Pearson Este artigo descreve as razões pelas quais você pode enfrentar erros aritméticos no Microsoft Excel97. Conteúdo do artigo: Valores atuais e exibidos Números de ponto flutuante Funções de planilha para arredondamento Padrão de ponto flutuante IEEE Este artigo parte do princípio de que você está familiarizado com o seguinte: Os conceitos de programação do Visual Basic para aplicativos (VBA) do Excel Os sistemas binários de números Pode haver tempos Que o valor que você vê em uma planilha do Excel não é igual ao valor que você acredita que ele deve ser. Existem geralmente duas causas possíveis deste problema. O primeiro é que os números não são exibidos para seus valores completos. A segunda é uma questão de design de computador. Nenhum dos dois são quotbugsquot ou problemas com o design do Microsoft Excel ou Windows. Excel armazena números de forma diferente que você pode tê-los formatado exibir na planilha. Em circunstâncias normais, Excel armazena valores numéricos como quotDoble Precision Floating Pointquot números, ou quotDoublesquot para abreviar. Estas são variáveis ​​de 8 bytes que podem armazenar números precisos para aproximadamente 15 casas decimais. Você pode ter apenas duas casas decimais exibidas na planilha, mas o valor subjacente tem as 15 casas decimais completas. O segundo problema surge do fato de que um computador, qualquer computador, não pode armazenar a maioria dos números fracionários com total precisão. Os computadores, em geral, usam o padrão IEEE (Instituto de Engenheiros Elétricos e Eletrônicos) para números de ponto flutuante. Este padrão fornece uma maneira de armazenar números fracionários no espaço limitado de um número de 8 bytes. Naturalmente, para a maioria dos números, alguma aproximação deve ser feita. Este artigo descreve e explica as causas para erros que são devido a qualquer uma das causas descritas acima: o número formatado exibido e os erros internos associados a números de ponto flutuante. Valores atuais e exibidos Em circunstâncias normais, o Excel sempre armazena e manipula números como números de 8 bytes quotDouble Precision Floating Pointquot, ou quotDoublesquot. Excels armazenamento interno do número não é afetado pela maneira que você pode escolher para formatar um número para exibição. Por exemplo, se uma célula contém a fórmula 1/3. Excel sempre trata esse valor como 0,3333133, independentemente de quantas casas decimais você escolher para exibir na planilha. Mesmo se você optar por exibir o valor como simples quot0.3quot, Excel ainda mantém o número completo como o valor da célula. Isso pode causar situações em que pode parecer que o Excel está fazendo um erro no cálculo, quando ele realmente não é. Por exemplo, suponha que temos a fórmula 1/3 em cada uma das três células A1: A3. Formatando essas células para um ponto decimal mostraria quot0.3quot em cada célula. Adicionar estas três células juntamente com a função SUM dará o resultado 1.0. Mas 0,3 0,3 0,3 é igual a 0,9 não 1,0, à direita O resultado parece estar incorreto. Claro, não é. Independentemente de como você tem as células formatadas para exibição, Excel usa o valor subjacente ao fazer cálculos. No exemplo, você não está realmente adicionando 0,3 0,3 0,3. Mas sim 0,333333333333333 0,333333333333333 0,333333333333333. Cuja soma é (quase) 1,0. O Excel oferece uma opção chamada quotPrecision As Displayedquot, que pode ser ativada na guia Cálculo na caixa de diálogo Opções (menu Ferramentas). Ativar essa opção força o Excel a usar os valores exibidos em seus cálculos, em vez dos números subjacentes. Com esta opção ativada, o exemplo acima seria realmente SUM para 0.9. Você deve ter muito cuidado ao usar esta opção, no entanto. Uma vez ativada, toda a precisão é perdida e não pode ser recuperada. Todas as células são calculadas com base no valor exibido. Esta opção aplica-se a toda a pasta de trabalho, não a uma célula específica ou intervalo de células. Números de ponto flutuante Excel, como quase todos os outros programas de computador, usa o padrão IEEE para números de ponto flutuante de precisão dupla. Este padrão é descrito em detalhes, no nível de bits, em uma seção posterior deste artigo. Podemos generalizá-lo, porém, para descrever como o Excel armazena números fracionários. Assim como os computadores armazenam inteiros como números binários, eles armazenam números fracionários como frações binárias. Os computadores armazenam um valor inteiro (número inteiro) como (x1 x2 x4 x8 x16 etc) em que x é o estado do bit. Se o bit estiver ligado, x1. Se o bit de off, x0. Nessa notação, qualquer inteiro pode ser armazenado exatamente. Por exemplo, o número 13 é armazenado em binário como 1101 que indica, lendo da esquerda para a direita, 18 14 02 11 13. Os números fraccionais são armazenados de uma maneira semelhante. No sistema binário, números fracionários são armazenados como a soma de uma série de frações: (x1 / 2 x1 / 4 x1 / 8 x1 / 16 etc) onde x é o estado do bit. Se o bit estiver ligado, x1. Se o bit de off, x0. Ao contrário dos inteiros, no entanto, nem todos os valores fracionários podem ser armazenados exatamente com precisão. Por exemplo, é impossível armazenar o número 1/10 0,1 em forma binária. Uma aproximação aproximada é (01/2 01/4 01/8 11/16 11/32 etc). Os computadores transportam esta operação para o equivalente a 15 casas decimais. Mesmo com esta precisão, muitos números são representados como uma aproximação do seu quottruequot ou quotanalyticquot valor. Por exemplo, é impossível descrever com precisão o número 1/10 em notação binária de 8 bytes (ou qualquer comprimento). Números de ponto flutuante podem vir muito perto de representar esse número, mas sempre haverá algum erro muito pequeno. É importante notar que esses erros e limitações em números fracionários não são realmente erros de todo. Nem são quotbugsquot nos programas. Essas são limitações bem conhecidas e bem documentadas dos sistemas aritméticos de ponto flutuante em quase todos os pacotes de software e dispositivos de hardware. Funções da planilha para arredondamento O Excel fornece várias funções para lidar com o arredondamento. Essas funções estão listadas abaixo. INT MROUND ROUNDDOWN ROUNDUP TRUNC NOTA: A função MROUND faz parte do suplemento ToolPak de análise para o Excel. Você deve ter esse pacote instalado para usar essas funções. Para instalar o ATP, vá para o menu Ferramentas, selecione Add-Ins. E coloque uma verificação ao lado do item Analysis ToolPak. Consulte a ajuda on-line para obter mais informações sobre essas funções. IEEE Floating Point Standard A seção descreve o formato interno de variáveis ​​de ponto flutuante de precisão dupla de 64 bits. O layout de um duplo é o seguinte: O tamanho de um flutuador é dependente da plataforma, embora um máximo de 1.8e308 com uma precisão de cerca de 14 dígitos decimais é um valor comum (o formato 64 bits IEEE). Precisão de ponto flutuante Os números de ponto flutuante têm precisão limitada. Embora dependa do sistema, o PHP normalmente usa o formato IEEE 754 de dupla precisão, o que proporcionará um erro relativo máximo devido ao arredondamento na ordem de 1.11e-16. Operações aritméticas não-elementares podem gerar erros maiores e, é claro, a propagação de erros deve ser considerada quando várias operações são compostas. Além disso, números racionais que são exatamente representáveis ​​como números de ponto flutuante na base 10, como 0,1 ou 0,7. Não têm uma representação exata como números de ponto flutuante na base 2, que é usado internamente, não importa o tamanho da mantissa. Portanto, eles não podem ser convertidos em suas contrapartes binárias internas sem uma pequena perda de precisão. Isso pode levar a resultados confusos: por exemplo, piso ((0.10.7) 10) normalmente retornará 7 em vez do esperado 8. Uma vez que a representação interna será algo como 7.9999999999999991118. . Portanto, nunca confie os resultados do número flutuante no último dígito e não compare números de ponto flutuante diretamente para a igualdade. Se for necessária maior precisão, as funções matemáticas de precisão arbitrária e as funções gmp estão disponíveis. Para uma explicação quotsimplequot, veja o guia de ponto flutuante raquo that039s também intitulado quotWhy não os meus números adicionar upquot Convertendo para flutuar Para obter informações sobre a conversão de seqüência de caracteres s para flutuar. Consulte Conversão de seqüência de caracteres em números. Para valores de outros tipos, a conversão é realizada convertendo o valor em inteiro primeiro e depois em float. Consulte Conversão para inteiro para obter mais informações. A partir do PHP 5, um aviso é lançado se um objeto é convertido para float. Comparando flutuadores Como observado no aviso acima, testar valores de ponto flutuante para a igualdade é problemático, devido à forma como eles são representados internamente. No entanto, há maneiras de fazer comparações de valores de ponto flutuante que trabalham em torno dessas limitações. Para testar valores de ponto flutuante para igualdade, um limite superior no erro relativo devido ao arredondamento é usado. Este valor é conhecido como epsilon da máquina, ou unidade roundoff, e é a menor diferença aceitável nos cálculos. A e b são iguais a 5 dígitos de precisão. Ltphp a 1.23456789 b 1.23456780 epsilon 0.00001 se (abs (a - b) lt epsilon) echo true gt NaN Algumas operações numéricas podem resultar em um valor representado pela constante NAN. Esse resultado representa um valor indefinido ou irrepresentável em cálculos de ponto flutuante. Qualquer comparação frouxa ou estrita deste valor contra qualquer outro valor, incluindo a si mesma, terá um resultado de FALSO. Como NAN representa qualquer número de valores diferentes, NAN não deve ser comparado a outros valores, incluindo-se, e em vez disso deve ser verificado usando isnan (). Notas de Contribuição do Usuário 30 notas apenas um comentário sobre algo a inserção de precisão de ponto flutuante, que vai: Isso está relacionado a. 0.3333333. Embora o autor provavelmente saiba do que estão falando, essa perda de precisão não tem nada a ver com a notação decimal, tem a ver com a representação como um binário de ponto flutuante em um registro finito, como quando 0,8 termina em decimal, é A repetição 0.110011001100. Em binário, que é truncado. 0,1 e 0,7 são também não-terminando em binário, então eles também são truncados, ea soma desses números truncados não adiciona até a representação binária truncada de 0,8 (razão pela qual (piso) (0,810) produz um diferente, mais Intuitivo, resultado). No entanto, uma vez que 2 é um fator de 10, qualquer número que termina em binário também termina em decimal. Dica de computação geral: Se você está mantendo o controle do dinheiro, faça você e seus usuários o favor de lidar com tudo internamente em centavos e fazer tanta matemática como você pode em números inteiros. Armazene valores em centavos se possível. Adicionar e subtrair em centavos. Em cada operação que envolva flutuadores, pergunte a si mesmo o que acontecerá no mundo real se eu receber uma fração de um centavo aqui e se a resposta é que esta operação irá gerar uma transação em centavos inteiros, não tente levar a fictícia precisão fracionária Que só vai estragar as coisas mais tarde. Ltphp binarydata32 pack (H. 00000000) float32 descompactar (f. Binarydata32) // 0.0 binarydata64 pack (H. 0000000000000000) float64 descompactar (d. Binarydata64) // 0.0 gt Eu recebo 0 tanto para números de 32 quanto de 64 bits. Mas, por favor, não use suas próprias funções para converter de flutuador para binário e vice-versa. Desempenho em loop no PHP é horrível. Usando pack / unpack você usa a codificação dos processadores, que está sempre correta. Em C você pode acessar os mesmos dados 32/64 como float / double ou 32/64 bit integer. Sem conversões. Para obter a codificação binária: ltphp float32 pack (f 5300231) binarydata32 descompactar (H. float32) // 0EC0A14A float64 pack (d. 5300231) binarydata64 descompactar (H. float64) // 000000C001385441 gt E meu exemplo de meio ano atrás: Ltphp binarydata32 pack (H. 0EC0A14A) float32 descompactar (f. Binarydata32) // 5300231 binarydata64 pack (H. 000000C001385441) float64 descompactar (d. Binarydata64) // 5300231 gt E por favor, mente os meninos Big and Little endian. Gostaria de apontar um recurso de PHP ponto flutuante apoio que não é claro em qualquer lugar aqui, e estava me deixando louco. Este teste (onde vardump diz que a0.1 e b0.1) se (agtb) echo blah Falhará em alguns casos devido a uma precisão oculta (problema padrão de C, que os docs do PHP não mencionam, então eu supus que eles tinham se livrado Do mesmo). Gostaria de salientar que eu originalmente pensei que este era um problema com os flutuadores sendo armazenados como seqüências de caracteres, então eu forçou-os a ser flutuadores e eles ainda didnt obter avaliados corretamente (provavelmente 2 problemas diferentes lá). Para corrigir, eu tive que fazer este horrível kludge (o equivelant de qualquer maneira): if (redondo (a, 3) gtround (b, 3)) echo blah Isso funciona. Obviamente, embora vardump diz que as variáveis ​​são idênticas, e eles DEVEM ser idênticos (iniciado em 0,01 e adicionado 0,001 repetidamente), theyre não. Há alguma precisão escondida lá que estava me fazendo rasgar meu cabelo para fora. Talvez isso deve ser adicionado à documentação Em alguns casos, você pode querer obter o valor máximo para um float sem obter INF. Vardump (1.8e308) geralmente mostrará: float (INF) Eu escrevi uma pequena função que irá iterar para encontrar o maior valor flutuante não-infinito. Ele vem com um multiplicador configurável e valores afim para que você possa compartilhar mais CPU para obter uma estimativa mais precisa. Eu não vi melhores valores com mais afinidade, mas bem, a possibilidade é aqui, então se você realmente a coisa vale a pena o tempo de CPU, apenas tentar affine mais. Melhores resultados parece ser com mul2 / affine1. Você pode jogar com os valores e ver o que você recebe. A coisa boa é que este método irá funcionar em qualquer sistema. Ltphp função floatmax (mul 2. affine 1) max 1 omax 0 enquanto ((string) max INF) para (i 0 i lt affine i) pmax 1 max omax enquanto ((string) max INF) omax máx max pmax pmax mul retorno Omax gt Tenha cuidado ao usar valores float em strings que são usados ​​como código mais tarde, por exemplo ao gerar código JavaScript ou instruções SQL. O float é realmente formatado de acordo com a configuração de local do navegador, o que significa que 0,23 resultará em 0,23. Imagine algo como isto: x 0.23 js var foo doBar (x) imprimir js Isso resultaria em um resultado diferente para os usuários com algumas localidades. Na maioria dos sistemas isso imprime: var foo doBar (0.23) mas quando, por exemplo, um usuário da Alemanha chega, seria diferente: var foo doBar (0,23) que é obviamente uma chamada diferente para a função. JavaScript não indicará um erro, argumentos adicionais são descartados sem aviso prévio, mas a função doBar (a) obteria 0 como parâmetro. Problemas semelhantes poderiam surgir em qualquer outro lugar (SQL, qualquer string usada como código em outro lugar). O problema persiste, se você usar o. Operador em vez de avaliar a variável na seqüência de caracteres. Então, se você realmente precisa ter a certeza de ter a seqüência corretamente formatado, use numberformat () para fazê-lo Eu estava a programação de um aplicativo de contabilidade em MySql que me obrigou a soma de uma coleção de carros alegóricos e garantir que eles igualam zero antes de cometer uma transação, Mas como visto acima uma soma de flutuadores nem sempre pode ser confiável (como foi o meu caso). I entretidas como se muito pequenas restante (como 1.4512431231e-14). Desde que eu tinha usado numberformat (num, 2) para definir a precisão dos números no banco de dados para apenas duas (2) casas decimais, quando chega o momento de calcular a soma eu simplesmente multiplicar cada número por dez (10), therby eliminando E casas decimais e deixando-me com inteiros para preform minha soma. Isso funcionou muito bem. Ltphp / hex2float (Converte valor hexadecimal de 8 dígitos para float (32bits de precisão única) Aceita valores hexadecimais de 8 dígitos em um uso de string: hex2float32n (429241f0) retorna - gt 73.128784179688 / função hex2float (número) binfinal sprintf (032b hexdec (número) ) Sign substr (binfinal 0. 1) exp substr (binfinal 1. 8) mantissa 1. substr (binfinal. 9) mantissa strsplit (mantissa) exp bindec (exp) - 127 significand 0 para (i 0 i lt 24 i Gt A caixa de precisão de ponto flutuante na prática significa: lt eco (69,1-chão (69,1)) gt Pense Thisll return 0.1 It doesnt - retorna 0.099999999999994 lt echo round ((69.1-floor (69.1))) gt Isso retorna 0.1 e é a solução que usamos Note que lt eco (4.1-floor (4.1)) gt retorna 0,1 - Então se você, como nós, testar isso com números baixos, você não vai entender como, de repente, seu script pára de funcionar, até que você gaste muito tempo, como nós, depurando-o. Então, isso é tudo adorável então. Uma maneira eficaz de comparar dois números reais (incluindo números de ponto flutuante) com alta precisão e ainda ser capaz de definir a precisão está usando a função BC Math bccomp () Por exemplo: ltphp a 1.23456789 b 1.23456780 precisão 5 if (bccomp (ab precision) 0) echo FALSE // FALSE gt Converte uma seqüência hexadecimal em um número flutuante IEEE 754 de 32 bits. (0) echo true // true gt ltphp a sprintf (.17f. 0.1 0.2) b 0.3 if (bccomp (ab 17) 0) Esta função é 2 vezes mais rápida que a função hexadecimal a 32bit abaixo. Esta função só altera tipos de dados (string para int) uma vez. Além disso, esta função é uma porta da função hexadecimal para 64 bits a partir de baixo. Ltphp função hexTo32Float (strHex) v hexdec (strHex) x (v amp ((1 ltlt 23) - 1)) (1 ltlt 23) (v gtgt 31 1) exp (v gtgt 23 amp 0xFF) - 127 return x pow // ext. Ex-23) gt ltphp // exemplo echo hexTo32Float (C4028000) // saídas: -522 echo hexTo32Float (457F9000) // saídas: 4089 echo hexTo32Float (2D7F5) // saídas: 6.00804264307E-39 echo hexTo32Float (0002D7F5) // outputs: 6.00804264307E-39 echo hexTo32Float (47D9F95E) // outputs: 111602.734375 gt A função retorna 5 para 5.000 porque se não houver ponto decimal, então o primeiro strpos será FALSE e FALSE lt 1 é TRUE assim que a condição Será ainda verdade. Deve ser verificado se strpos retorna uma posição válida: ltphp function str2num (str) if (strpos (str.) FALSE ampamp strpos (str.) FALSE ampamp strpos (str. Str (str. Str) str strtr (str.,.) Else str strreplace (,. Str) return (float) str gt PHP muda da notação decimal padrão para a notação exponencial para certos flutuadores especiais. Você pode ver uma lista parcial de tais valores especiais com isto: ltphp para (tmp 0. i 0 i lt 100 i) tmp 100000 ronda de eco (tmp), n gt Assim, se você adicionar dois flutuadores, acabar com um valor especial , por exemplo 1.2E6, then put that value unmodified into an update query to store the value in a decimal column, say, you will likely get a failed transaction, since the database will see 1.2E6 as varchar data, not decimal. Likewise, you will likely get an XSD validation error if you put the value into xml. I have to be honest: this is one of the strangest things I have seen in any language in over 20 years of coding, and it is a colossal pain to work around. The was talk about converting 32 and 64 bit IEEE754 binary numbers to PHP float. The issue isnt as much converting, since they are already in binary form, as it is casting. PHP doesnt allow direct accessing of memory, but you can still get around a bit. The right was to read floats (32 and 64 bit) is this: ltphp binarydata32 pack ( H. 0EC0A14A ) float32 unpack ( f. binarydata32 ) binarydata64 pack ( H. 000000C001385441 ) float64 unpack ( d. binarydata64 ) vardump ( float32. float64. float32 float64 ) gt The result of dump(): ltphp array( 1 ) 1 gt float ( 5300231 ) array( 1 ) 1 gt float ( 5300231 ) bool ( true ) gt Note: mind the Big and Little endian boys In MySQL, many floating point number types can have a range specified using 2 values, the precision and the scale E. g. float(precision, scale) for the datatype. This syntax means a number may be ltprecisiongt bits long, but may only have ltscalegt bits after the decimal point. Por exemplo. a float(5,2) field may have the values -999.99 to 999.99. Here is a function to validate a PHP float using this syntax: ltphp function validatefloat ( float. precision. scale ) max (float) strpad ( . precision - scale. 9 ). .. strpad ( . scale. 9 ) min (float) - max if(( float lt min ) ( float gt max )) return false else return true gt In the gettype() manual, it says (for historical reasons double is returned in case of a float, and not simply float) . However, I think that internally PHP sometimes uses the C double definition (i. e. a double is twice the size of a float/real). See the example below: lt //Function required to reverse a string on blocks of two function strrevx(s, x 2) if (x lt 1) return strrev(s) else return (implode(arrayreverse(arraymap(implode, arraychunk(strsplit(s), x))))) echo double pack. PHPEOL tst pack(d, 1.6) vardump(strrevx(bin2hex(tst))) tst pack(d, 8-6.4) vardump(strrevx(bin2hex(tst))) echo float pack. PHPEOL tst pack(f, 1.6) vardump(strrevx(bin2hex(tst))) tst pack(f, 8-6.4) vardump(strrevx(bin2hex(tst))) gt (The strrevx-bin2hex combination is just to give printable characters.) Given that PHP treats doubles and floats identically, Id expected the same string as output, however, the output is: double pack string(16) 3ff999999999999a //Here you see that there is a minute difference. string(16) 3ff9999999999998 float pack string(8) 3fcccccd //. which doesnt exist here string(8) 3fcccccd So, as an alternative to using float1 float2 one could use pack(f, float1) pack (f, float2) with a big footnote that one should really remember that one is reducing your accuracy of the comparison. AFAIK is this the only way (apart from epsilon methods) to securely compare two floats. Calculations involving float types become inaccurate when it deals with numbers with more than approximately 8 digits long where ever the decimal point is. This is because of how 32bit floats are commonly stored in memory. This means if you rely on float types while working with tiny fractions or large numbers, your calculations can end up between tiny fractions to several trillion off. This usually wont matter when converting to binary memory storage form and editing many applications float memory addresses directly, or dealing with smaller length numbers. But if youre working with larger scale numbers and decimals, its best to switch to working with other types: www/manual/en/refs. math Here is a function to convert an exponential-format float to a decimal-format float e. g. 1.6e12 to 1600000000000. It will help addressing the problem specified by kjohnson above. I have tested it, but not in any real world situation so any feedback/improvements/bug-reports would be appreciated. ltphp function exptodec ( floatstr ) // formats a floating point number string in decimal notation, supports signed floats, also supports non-standard formatting e. g. 0.2e2 for 20 // e. g. 1.6E6 to 1600000, -4.566e-12 to -0.000000000004566, 34e10 to 340000000000 // Author: Bob // make sure its a standard php float string (i. e. change 0.2e2 to 20) // php will automatically format floats decimally if they are within a certain range floatstr (string)((float)( floatstr )) // if there is an E in the float string if(( pos strpos ( strtolower ( floatstr ), e )) false ) // get either side of the E, e. g. 1.6E6 gt exp E6, num 1.6 exp substr ( floatstr. pos 1 ) num substr ( floatstr. 0. pos ) // strip off num sign, if there is one, and leave it off if its (not required) if((( numsign num 0 ) ) ( numsign - )) num substr ( num. 1 ) else numsign if( numsign ) numsign // strip off exponential sign ( or - as in E6) if there is one, otherwise throw error, e. g. E6 gt if((( expsign exp 0 ) ) ( expsign - )) exp substr ( exp. 1 ) else triggererror ( Could not convert exponential notation to decimal notation: invalid float string floatstr . EUSERERROR ) // get the number of decimal places to the right of the decimal point (or 0 if there is no dec point), e. g. 1.6 gt 1 rightdecplaces (( decpos strpos ( num. . )) false ). 0. strlen ( substr ( num. decpos 1 )) // get the number of decimal places to the left of the decimal point (or the length of the entire num if there is no dec point), e. g. 1.6 gt 1 leftdecplaces ( decpos false ). strlen ( num ). strlen ( substr ( num. 0. decpos )) // work out number of zeros from exp, exp sign and dec places, e. g. exp 6, exp sign , dec places 1 gt num zeros 5 if( expsign ) numzeros exp - rightdecplaces else numzeros exp - leftdecplaces // build a string with numzeros zeros, e. g. 0 5 times gt 00000 zeros strpad ( . numzeros. 0 ) // strip decimal from num, e. g. 1.6 gt 16 if( decpos false ) num strreplace ( .. . num ) // if positive exponent, return like 1600000 if( expsign ) return numsign. Num. zeros // if negative exponent, return like 0.0000016 else return numsign. 0.. zeros. num // otherwise, assume already in decimal notation and return else return floatstr gt As m dot lebkowskiphp at gmail dot com (www/language. types. float81416 ) noted 9 comments below : When PHP converts a float to a string, the decimal separator used depends on the current locale conventions. However, to declare a floating point number, one must always use a full stop otherwhise the code would be locale dependent (imagine the nightmare): ltphp float 1.5 // float(1.5) float 1. 5 // Parse error: syntax error, unexpected , float (float) 1.5 // float(1.5) float (float) 1,5 // float(1) gt Now, if you have a string containing a localized number, you can convert it back to a floating point number using the following function: ltphp / Convert a localized number string into a floating point number param string sNumber The localized number string to convert. return float The converted number. / function str2num ( sNumber ) aConventions localeConv () sNumber trim ((string) sNumber ) bIsNegative ( 0 aConventions nsignposn ampamp ( sNumber ampamp ) sNumber ) sCharacters aConventions decimalpoint . aConventions mondecimalpoint . aConventions negativesign sNumber pregreplace ( /. pregquote ( sCharacters ). d/. . trim ((string) sNumber )) iLength strlen ( sNumber ) if ( strlen ( aConventions decimalpoint )) sNumber strreplace ( aConventions decimalpoint , .. sNumber ) if ( strlen ( aConventions mondecimalpoint )) sNumber strreplace ( aConventions mondecimalpoint , .. sNumber ) sNegativeSign aConventions negativesign if ( strlen ( sNegativeSign ) ampamp 0 aConventions nsignposn ) bIsNegative ( sNegativeSign sNumber sNegativeSign sNumber ) if ( bIsNegative ) sNumber strreplace ( aConventions negativesign , . sNumber ) fNumber (float) sNumber if ( bIsNegative ) fNumber - fNumber return fNumber gt Example: ltphp setLocale ( LCALL. frBE. UTF-8 ) // decimal separator is now a comma float - 123456.789 string (string) float vardump ( float ) // float(-123456,789) vardump ( string ) // string(11) -123456,789 vardump ((float) string ) // float(-123456) vardump ( str2num ( string )) // float(-123456,789) gt It also works with strings returned by the numberformat() function: ltphp setLocale ( LCALL. frBE. UTF-8 ) // decimal separator is now a comma conv localeconv () float - 123456.789 string conv intcurrsymbol . numberformat ( float. conv fracdigits , conv decimalpoint , conv thousandssep ) vardump ( float ) // float(-123456,789) vardump ( string ) // string(15) EUR -123.456,79 vardump ((float) string ) // float(0) vardump ( str2num ( string )) // float(-123456,79) gt Convert locale string into float number ltphp function str2num ( str ) if( strpos ( str. . ) lt strpos ( str. , )) str strreplace ( .. . str ) str strtr ( str. ,. . ) else str strreplace ( ,. . str ) return (float) str str2num ( 25,01 ) //25.01 str2num ( 2.5,01 ) //25.01 str2num ( 25.01 ) //25.01 str2num ( 2,5.01 ) //25.01 gt Floating point values have a limited precision. Hence a value might not have the same string representation after any processing. That also includes writing a floating point value in your script and directly printing it without any mathematical operations. If you would like to know more about floats and what IEEE 754 is read this: docs. sun/source/806-3568/ncggoldbergType float Because exponents are stored in an unsigned form, the exponent is biased by half its possible value. For type float, the bias is 127 for type double, it is 1023. You can compute the actual exponent value by subtracting the bias value from the exponent value. The mantissa is stored as a binary fraction greater than or equal to 1 and less than 2. For types float and double, there is an implied leading 1 in the mantissa in the most-significant bit position, so the mantissas are actually 24 and 53 bits long, respectively, even though the most-significant bit is never stored in memory. Instead of the storage method just described, the floating-point package can store binary floating-point numbers as denormalized numbers. Denormalized numbers are nonzero floating-point numbers with reserved exponent values in which the most-significant bit of the mantissa is 0. By using the denormalized format, the range of a floating-point number can be extended at the cost of precision. You cannot control whether a floating-point number is represented in normalized or denormalized form the floating-point package determines the representation. The floating-point package never uses a denormalized form unless the exponent becomes less than the minimum that can be represented in a normalized form. The following table shows the minimum and maximum values you can store in variables of each floating-point type. The values listed in this table apply only to normalized floating-point numbers denormalized floating-point numbers have a smaller minimum value. Note that numbers retained in 80 x 87 registers are always represented in 80-bit normalized form numbers can only be represented in denormalized form when stored in 32-bit or 64-bit floating-point variables (variables of type float and type long). Range of Floating-Point Types 1.175494351 E 38 3.402823466 E 38 2.2250738585072014 E 308 1.7976931348623158 E 308 If precision is less of a concern than storage, consider using type float for floating-point variables. Conversely, if precision is the most important criterion, use type double. Floating-point variables can be promoted to a type of greater significance (from type float to type double). Promotion often occurs when you perform arithmetic on floating-point variables. This arithmetic is always done in as high a degree of precision as the variable with the highest degree of precision. For example, consider the following type declarations: In the preceding example, the variable fshort is promoted to type double and multiplied by flong then the result is rounded to type float before being assigned to fshort . In the following example (which uses the declarations from the preceding example), the arithmetic is done in float (32-bit) precision on the variables the result is then promoted to type double:

No comments:

Post a Comment