Eu sei, a pergunta parece estranha. Os programadores às vezes pensam demais. Por favor, leia em ...
No IC, use signed
e unsigned
números inteiros muito. Eu gosto do fato de o compilador me avisar se eu fizer coisas como atribuir um número inteiro assinado a uma variável não assinada. Recebo avisos se comparar assinados com números inteiros não assinados e muito mais.
Eu gosto desses avisos. Eles me ajudam a manter meu código correto.
Por que não temos o mesmo luxo para carros alegóricos? Uma raiz quadrada definitivamente nunca retornará um número negativo. Também há outros lugares onde um valor flutuante negativo não tem significado. Candidato perfeito para um carro alegórico não assinado.
Btw - Eu não estou realmente interessado no único bit extra de precisão que eu poderia obter removendo o bit de sinal dos carros alegóricos. Estou super feliz com float
s como estão agora. Eu gostaria de marcar um float como não assinado às vezes e receber o mesmo tipo de aviso que recebo com números inteiros.
Não conheço nenhuma linguagem de programação que suporte números de ponto flutuante não assinados.
Alguma idéia de por que eles não existem?
EDITAR:
Eu sei que o x87 FPU não tem instruções para lidar com carros alegóricos não assinados. Vamos apenas usar as instruções de flutuação assinadas. O uso indevido (por exemplo, abaixo de zero) pode ser considerado um comportamento indefinido da mesma maneira que o excesso de números inteiros assinados é indefinido.
Respostas:
Por que o C ++ não tem suporte para flutuadores não assinados é porque não há operações equivalentes de código de máquina para a CPU executar. Portanto, seria muito ineficiente apoiá-lo.
Se o C ++ o suportasse, você às vezes usaria um flutuador não assinado e não perceberia que seu desempenho acabou de ser morto. Se o C ++ o suportasse, todas as operações de ponto flutuante precisariam ser verificadas para ver se estão assinadas ou não. E para programas que realizam milhões de operações de ponto flutuante, isso não é aceitável.
Portanto, a pergunta seria por que os implementadores de hardware não o suportam. E acho que a resposta é que não havia um padrão de flutuação sem sinal definido originalmente. Como os idiomas gostam de ser compatíveis com versões anteriores, mesmo que fossem adicionados, os idiomas não poderiam fazer uso dele. Para ver a especificação de ponto flutuante, consulte o ponto flutuante padrão IEEE 754 .
Você pode evitar um tipo de ponto flutuante não assinado criando uma classe de flutuação não assinada que encapsule um float ou double e emita avisos se você tentar passar um número negativo. Isso é menos eficiente, mas provavelmente se você não os estiver usando intensamente, não se importará com essa pequena perda de desempenho.
Definitivamente, vejo a utilidade de ter um carro alegórico não assinado. Mas o C / C ++ tende a escolher a eficiência que funciona melhor para todos que a segurança.
fonte
int
acontece com todas as verificações de tipo relacionadas a sinais, podem ocorrer em tempo de compilação. O OP sugere que issounsigned float
seria implementado regularmentefloat
com verificações em tempo de compilação para garantir que determinadas operações não significativas nunca sejam executadas. O código da máquina e o desempenho resultantes podem ser idênticos, independentemente de seus carros alegóricos serem assinados ou não.Há uma diferença significativa entre números inteiros assinados e não assinados em C / C ++:
valores assinados deixam o bit superior inalterado (extensão do sinal), valores não assinados limpam o bit superior.
O motivo pelo qual não há flutuação não assinada é que você encontra rapidamente todos os tipos de problemas se não houver valores negativos. Considere isto:
Qual valor c tem? -8 Mas o que isso significaria em um sistema sem números negativos. FLOAT_MAX - 8 talvez? Na verdade, isso não funciona como FLOAT_MAX - 8 é FLOAT_MAX devido a efeitos de precisão, portanto as coisas são ainda mais complicadas. E se fosse parte de uma expressão mais complexa:
Isso não é um problema para números inteiros devido à natureza do sistema de complemento do 2.
Considere também as funções matemáticas padrão: sin, cos e tan funcionariam apenas pela metade dos valores de entrada, você não poderia encontrar o log de valores <1, não conseguiria resolver equações quadráticas: x = (-b +/- root ( bb - 4.ac)) / 2.a e assim por diante. De fato, provavelmente não funcionaria para nenhuma função complexa, pois elas tendem a ser implementadas como aproximações polinomiais que usariam valores negativos em algum lugar.
Portanto, carros alegóricos não assinados são bastante inúteis.
Mas isso não significa dizer que uma classe que alcance valores flutuantes não seja útil; convém fixar valores em um determinado intervalo, por exemplo, cálculos RGB.
fonte
2's complement
, não haverá problema em ter carros alegóricos não assinados?value >> shift for signed values leave the top bit unchanged (sign extend)
Você tem certeza sobre isso? Eu pensei que era um comportamento definido pela implementação, pelo menos para valores assinados negativos.0.0
, ou possivelmente Inf ou NaN. Ou apenas seja Comportamento indefinido, como o OP sugerido em uma edição da pergunta. Re: funções trig: por isso não defina versões de entrada não assinadasin
e assim por diante, e certifique-se de tratar seu valor de retorno como assinado. A pergunta não estava propondo substituir float por float não assinado, apenas adicionandounsigned float
como um novo tipo.(Além disso, o Perl 6 permite escrever
e então você pode usar
Nonnegative::Float
como faria com qualquer outro tipo.)Não há suporte de hardware para operações de ponto flutuante não assinadas, portanto, o C não o oferece. C é projetado principalmente para ser "montagem portátil", ou seja, o mais próximo possível do metal, sem ser amarrado a uma plataforma específica.
[editar]
C é como montagem: o que você vê é exatamente o que você recebe. Um implícito "Vou verificar se esse float não é negativo para você" vai contra a sua filosofia de design. Se você realmente deseja, pode adicionar
assert(x >= 0)
ou semelhante, mas você deve fazer isso explicitamente.fonte
of ...
não analisa.Acredito que o int não assinado foi criado devido à necessidade de uma margem de valor maior do que o int assinado poderia oferecer.
Um flutuador tem uma margem muito maior, portanto, nunca houve uma necessidade "física" de um flutuador não assinado. E, como você se destaca na sua pergunta, a precisão adicional de 1 bit não é motivo para matar.
Edit: Depois de ler a resposta de Brian R. Bondy , tenho que modificar minha resposta: ele está definitivamente certo que as CPUs subjacentes não tiveram operações de flutuação não assinadas. No entanto, mantenho minha convicção de que essa foi uma decisão de design com base nos motivos que afirmei acima ;-)
fonte
Eu acho que Treb está no caminho certo. É mais importante para números inteiros que você tenha um tipo correspondente não assinado. Esses são os que são usados na troca de bits e nos mapas de bits . Um pouco de sinal entra no caminho. Por exemplo, deslocando à direita um valor negativo, o valor resultante é a implementação definida em C ++. Fazer isso com um número inteiro sem sinal ou transbordando, define semântica perfeitamente definida, porque não existe esse caminho.
Portanto, para números inteiros, pelo menos, a necessidade de um tipo não assinado separado é mais forte do que apenas dar avisos. Todos os pontos acima não precisam ser considerados para carros alegóricos. Portanto, acho que não há necessidade real de suporte de hardware para eles, e C já não os apoiará nesse momento.
fonte
O C99 suporta números complexos e uma forma genérica do tipo sqrt, portanto,
sqrt( 1.0 * I)
será negativo.Os comentaristas destacaram um leve brilho acima, pois eu estava me referindo à
sqrt
macro genérica do tipo, e não à função, e ele retornará um valor escalar de ponto flutuante truncando o complexo para seu componente real:Ele também contém um peido cerebral, pois a parte real do sqrt de qualquer número complexo é positiva ou zero e sqrt (1,0 * I) é sqrt (0,5) + sqrt (0,5) * I não -1,0.
fonte
sqrt(-0.0)
freqüentemente produz-0.0
. Claro que -0,0 não é um valor negativo .Eu acho que depende que as especificações de ponto flutuante IEEE sejam assinadas apenas e que a maioria das linguagens de programação as use.
Artigo da Wikipedia sobre números de ponto flutuante IEEE-754
Edit: Além disso, como observado por outros, a maioria dos hardwares não suporta flutuadores não negativos, portanto, o tipo normal de flutuadores é mais eficiente, pois existe suporte de hardware.
fonte
Penso que a principal razão é que os flutuadores não assinados teriam usos realmente limitados em comparação com ints não assinados. Não acredito no argumento de que é porque o hardware não suporta. Os processadores mais antigos não tinham nenhuma capacidade de ponto flutuante; tudo era emulado em software. Se flutuadores não assinados fossem úteis, eles seriam implementados primeiro no software e o hardware seguiria o exemplo.
fonte
Tipos inteiros não assinados em C são definidos de maneira a obedecer às regras de um anel algébrico abstrato. Por exemplo, para qualquer valor X e Y, adicionar XY a Y produzirá X. É garantido que os tipos inteiros não assinados obedeçam a essas regras em todos os casos que não envolvam conversão para ou de qualquer outro tipo numérico [ou tipos não assinados de tamanhos diferentes] , e essa garantia é um dos recursos mais importantes desses tipos. Em alguns casos, vale a pena renunciar à capacidade de representar números negativos em troca das garantias extras que somente os tipos não assinados podem fornecer. Tipos de ponto flutuante, assinados ou não, não podem cumprir todas as regras de um anel algébrico [por exemplo, eles não podem garantir que X + YY será igual a X] e, na verdade, o IEEE não ' até permite que eles cumpram as regras de uma classe de equivalência [exigindo que certos valores se comparem desiguais]. Eu não acho que um tipo de ponto flutuante "não assinado" possa respeitar quaisquer axiomas que um tipo de ponto flutuante comum não possa, por isso não tenho certeza de quais vantagens ele ofereceria.
fonte
IHMO, é porque o suporte a tipos de ponto flutuante assinados e não assinados em hardware ou software seria muito problemático
Para tipos inteiros, podemos utilizar a mesma unidade lógica para operações inteiras assinadas e não assinadas na maioria das situações, usando a propriedade nice do complemento 2, porque o resultado é idêntico nesses casos para add, sub, mul não-alargamento e operações bit a bit. Para operações que diferenciam entre versão assinada e não assinada, ainda podemos compartilhar a maioria da lógica . Por exemplo
INT_MIN
. Também teoricamente possível, provavelmente não é usado em hardware, mas é útil em sistemas que suportam apenas um tipo de comparação (como 8080 ou 8051)Os sistemas que usam o complemento 1 também precisam de uma pequena modificação na lógica, porque é simplesmente o bit de transporte envolvido no bit menos significativo. Não tenho certeza sobre os sistemas de magnitude de sinal, mas parece que eles usam o complemento de 1 internamente, então o mesmo se aplica
Infelizmente , não temos esse luxo para os tipos de ponto flutuante. Simplesmente liberando o bit de sinal, teremos a versão não assinada. Mas então para que devemos usar esse pedaço?
Mas ambas as opções precisam de um somador maior para acomodar a faixa de valor mais ampla. Isso aumenta a complexidade da lógica enquanto o bit superior do somador fica lá sem uso na maioria das vezes. Mais circuitos serão necessários para multiplicações, divisões ou outras operações complexas
Em sistemas que usam ponto flutuante de software, você precisa de 2 versões para cada função que não era esperada durante o tempo em que a memória era muito cara ou seria necessário encontrar uma maneira "complicada" de compartilhar partes das funções assinadas e não assinadas
No entanto , o hardware de ponto flutuante existia muito antes de C ser inventado , então acredito que a escolha em C foi devido à falta de suporte de hardware devido ao motivo mencionado acima
Dito isto, existe várias especializados formatos sem assinatura de ponto flutuante, principalmente para fins de processamento de imagem, como o tipo de ponto flutuante 10 e 11-bit do grupo Khronos
fonte
Eu suspeito que é porque os processadores subjacentes direcionados por compiladores C não têm uma boa maneira de lidar com números de pontos flutuantes não assinados.
fonte
Boa pergunta.
Se, como você diz, é apenas para avisos em tempo de compilação e nenhuma alteração no comportamento deles, o hardware subjacente não é afetado e, como tal, seria apenas uma alteração do C ++ / Compilador.
Já ganhei o mesmo anteriormente, mas a questão é: não ajudaria muito. Na melhor das hipóteses, o compilador pode encontrar atribuições estáticas.
Ou minimamente mais longo
Mas é isso aí. Com tipos inteiros não assinados, você também obtém uma envolvente definida, a saber, que se comporta como aritmética modular.
depois disso 'uc' mantém o valor 255.
Agora, o que um compilador faria com o mesmo cenário, dado um tipo de flutuação não assinado? Se os valores não forem conhecidos no momento da compilação, será necessário gerar o código que primeiro executa os cálculos e, em seguida, faz uma verificação de sinal. Mas e quando o resultado de tal cálculo seria "-5,5" - qual valor deve ser armazenado em um float declarado sem sinal? Pode-se tentar aritmética modular como para tipos integrais, mas isso vem com seus próprios problemas: O maior valor é indiscutivelmente infinito .... isso não funciona, você não pode ter "infinito - 1". Indo para o maior valor distinto que ele pode conter também não funcionará realmente, pois você encontra a precissão. "NaN" seria um candidato.
Por fim, isso não seria um problema com números de pontos fixos, pois o módulo está bem definido.
fonte