Existe uma linguagem de programação em que 1/6 se comporta da mesma forma que 1.0 / 6.0?

11

Enquanto programava em C ++ há alguns dias, cometi esse erro (que tenho histórico de cometê-lo!). Em uma parte do meu código, eu tinha 1/6 e esperava que fosse 0,16666666666, o que não é o caso. Como todos sabem, o resultado é 0 - C, C ++, Java, Python, todos se comportam da mesma maneira.

Eu publico na minha página do Facebook e agora há um debate sobre se existe uma linguagem de programação onde 1/6o mesmo se comporta 1.0/6.0.

Pouya
fonte
5
Haskell. 1/6 = 0.16666666666666666
t123
O PowerShell gera 0,166666666666667, o que me surpreendeu, pois 1 é um número inteiro. Aposto que existem outras linguagens .NET que geram o valor que você esperava.
johnl
Existe, em teoria, um número ilimitado deles. Aqui está outro: Rebol , assim como derivados como Orca, Red, e assim por diante. >> 1 / 6->== 0.166666666666667
Izkata
Lua faz isso. Ele tem apenas um único tipo de número , que geralmente é igual ao dobro de C.
Machado
Em Clojure 1/6é realmente 1/6 (tipo fracionário) que, coagido a Double, é 1,66666 ...
kaoD

Respostas:

17

Todo mundo esqueceu Pascal?

1/6rendimentos 0.1666666...(com qualquer precisão suportada).

1 div 6 rendimentos 0

É discutível se a regra C é um erro. Quase todos os operadores aritméticos de C, onde os operandos são do mesmo tipo, produzem um resultado do mesmo tipo. Há algo a ser dito para consistência.

Além disso, como C é direcionado principalmente ao código no nível do sistema, a maioria dos programas em C não usa ponto flutuante. Ao mesmo tempo, adicionar acidentalmente código de ponto flutuante a um programa que não precisava dele poderia ser um problema sério. Provavelmente ainda é esse o caso de pequenos sistemas embarcados - que, novamente, são um grande alvo para C.

Na maioria dos programas C, truncar a divisão inteira provavelmente é exatamente o que você deseja.

Se 1 / 6produziu um resultado de ponto flutuante em C, então:

  • Seria uma inconsistência no idioma.
  • O padrão teria que fazer uma escolha arbitrária de qual tipo de ponto flutuante usar para o resultado ( doublepode parecer a escolha natural, mas você pode preferir a precisão extra de long double)
  • O idioma ainda precisaria ter uma operação para divisão inteira; executar adição de ponto flutuante e, em seguida, truncar provavelmente não seria bom o suficiente.

C poderia ter fornecido operadores separados para os dois tipos de divisão, mas o segundo ponto acima ainda se aplicaria: qual dos três tipos de ponto flutuante seria usado para o resultado? E como é fácil obter a divisão de ponto flutuante, se você precisar (use uma constante de ponto flutuante para um ou ambos os operandos ou converta um ou ambos os operandos para um tipo de ponto flutuante), aparentemente não era ' Não considerou isso importante.

Na versão de 1974 do manual C (quatro anos antes da publicação da primeira edição da K&R), Ritchie nem menciona a possível confusão:

O binário / operador indica divisão. As mesmas considerações de tipo da multiplicação se aplicam

que diz que, se ambos os operandos são do tipo intou char, o resultado é do tipo int.

Sim, é uma fonte de confusão para alguns programadores de C, especialmente iniciantes - mas C não é conhecido por ser muito amigável para iniciantes.

Keith Thompson
fonte
5
Pascal. Obtendo detalhes direita antes C tem que eles estavam errados ™.
Mason Wheeler
E então Algol foi uma melhoria em relação a seus sucessores (no número em que C e Pascal estão).
APROGRAMmer
Pascal - recebendo o direito de detalhes (dar ou tomar um fator de 10)
Martin Beckett
1
Eu escrevi originalmente 1.666666..., o que está claramente errado. Meu coxo desculpa é que o programa de teste Pascal eu escrevi impresso1.6666666666666667E-0001
Keith Thompson
16

Na verdade, esse comportamento foi alterado no Python 3 e agora se comporta como o esperado ( //agora é usado para divisão inteira).

sepp2k
fonte
Obrigado. Você tem alguma outra linguagem de programação? Família básica, talvez?
Pouya
1
@Pouya: Esse comportamento é padrão para a família Pascal. /sempre produz um valor de ponto flutuante e um operador separado ( div) é usado para divisão inteira.
Mason Wheeler
13

Fora de idiomas importantes, JavaScript. 1,0 / 6,0 = 1/6 = 0,1666666666666666666.

Eu não vejo isso como surpreendente. Como regra geral, se um idioma distingue entre tipos numéricos de número inteiro e de ponto flutuante, a divisão de dois números inteiros produzirá um número inteiro truncado em vez de flutuante. Caso contrário, provavelmente será o padrão para operações de ponto flutuante. Esse deve ser o comportamento esperado da parte do programador.

Lembre-se de que há outras coisas que também podem estar em jogo aqui, como o operador de divisão inteira separado já mencionado ou a conversão implícita de tipos.

scrwtp
fonte
6
Esta não é "uma regra de ouro". É uma regra de C e um punhado de idiomas que copiaram cegamente os erros de C.
Mason Wheeler
4
@MasonWheeler: FORTRAN "copiou cegamente o erro de C"? Pessoalmente, acredito que linguagens bem projetadas devem usar operadores separados para divisão truncada versus divisão aproximada de quantidades inteiras (e também, btw, para valor e igualdade referencial), mas a decisão de design nos dias do FORTRAN provavelmente era razoável. Isso não significa que todos os idiomas devam fazer as coisas da maneira que o FORTRAN fez nos anos 50.
Supercat 09/08
3
Os idiomas de nível inferior precisam fazer essas distinções. Linguagens dinâmicas / de nível superior geralmente são melhores sem elas. É uma troca de design. Aprecio apenas ter um construtor / tipo Number idiota em JS, mas imagino que sentiria falta de JS ao tentar escrever um mecanismo 3D de alto desempenho sem controle de tipo mais rigoroso. O JS pode ter utilidade sobreposta a outras linguagens, mas acho que alguém nunca considerará uma opção para escrever coisas de alto desempenho mais próximas do cromo.
Erik Reppen
2
A matemática fora da programação considera regras somente de número inteiro para divisão.
Erik Reppen
5
@ MasonWheeler: A programação não é pura matemática. Matematicamente, 1/6 é um número racional e não pode ser representado exatamente pelo número do ponto flutuante binário. A única representação precisa é como uma relação com um denominador seis vezes o numerador.
Kevin cline
7

Existem muitos idiomas em que ((1/6)*6)resulta em 1, e não em 0. Por exemplo, PL / SQL, muitos dialetos BASIC, Lua.

Acidentalmente, em todos esses idiomas 1/6 resulta em 0,1666666667 ou 0,16666666666667 ou algo semelhante. Eu escolhi a ((1/6) * 6) == 1 variante para se livrar dessas pequenas diferenças.

user281377
fonte
7
Essa não é a questão.
Roc Martí
20
Acidentalmente, em todos esses idiomas 1/6 resulta em 0,1666666667 ou 0,16666666666667 ou algo semelhante. Escolhi a ((1/6)*6)==1variante para se livrar dessas pequenas diferenças, mas parece que superestimei as habilidades matemáticas de algumas pessoas.
User281377
1
@ RocMartí sim, ele realmente é ...
MattDavey
1
Eu ficaria surpreso em ver (1.0 / 6.0) * 6 sendo exatamente igual a 1! O arredondamento do resultado de (1.0 / 6.0) levará a uma pequena diferença. (Embora haja algumas línguas que padrão a precisão infinita)
Sjoerd
1
@ Sjoerd: Não é de surpreender que seja exato, na verdade. Considere em decimal o cenário de 1/11 * 11 com todos os valores precisos para cinco algarismos significativos. O valor de 1/11 é 9,0909 * 10 ^ -2. Multiplique por 11 e obterá 99,9999 * 10 / -2 antes do arredondamento. Arredonde para cinco algarismos significativos e o resultado será 1.0000 * 10 ^ 0. Observe que a chave é que a mantissa de 1/6 é "... 0101010101 ...". Se o último bit de uma representação for um "1", multiplicá-lo por seis e arredondar resultará em 1. Se o último bit for zero, não o faria.
Supercat 09/08
3

Haskell trata 1/6 e 1.0 / 6.0 como sendo idênticos 0.16666666666666666. Também processa 1 / 6.0 e 1.0 / 6 como sendo o mesmo valor também.

Isso ocorre porque os tipos numéricos básicos em Haskell não são exatamente os mesmos de outros idiomas. A verdadeira divisão inteira é um pouco ... complicada.

Engenheiro Mundial
fonte
2

Sim, Perl faz. O one-liner

perl -e '$x=1/6;print "$x\n";'

resulta na saída de:

0.166666666666667

Eu acredito que o PHP funciona da mesma maneira.

Editado para adicionar: Eu também acredito que uma condição necessária (mas não suficiente) 1/6 == 1.0/6.0para o idioma em questão seja fracamente digitada.


fonte
Por que diabos seria necessária uma digitação fraca (o que quer que isso signifique)? Basta definir / para (também) a divisão de flutuação média no caso de ambos os argumentos serem números inteiros.
1
@delnan - en.wikipedia.org/wiki/Weak_typing Suponho que poderia ser possível ter uma linguagem fortemente digitado em que /está sobrecarregado automaticamente dependendo dos tipos dos argumentos, mas que parece ser uma violação do princípio do menor Astonishment para me ...
2
Digitação fraca / forte está mal definida (como o wiki também implica), evite-a e seja específico. Entendo que sua definição proíbe a conversão implícita, mas não o polimorfismo ad-hoc? Nesse caso, considere o polimorfismo numérico de Haskell, que não possui conversões implícitas, mas que é bem executado (como em, funciona 99% do tempo e pode ser compreendido por mortais). E por que isso seria surpreendente? Seria muito mais surpreendente (para não dizer irritante) para mim se eu tivesse que adicionar um número de pontos a cada instância de qualquer operador, dependendo da precisão exata que eu desejasse.
2
@ JackManey Acho que para a maioria dos novatos é muito mais surpreendente que 1/2 seja igual a 0 do que se dividir dois números inteiros resultar em um dobro. Depois que todos os números inteiros também não estão fechados na divisão em matemática. Também como delnan aponta, Haskell é um exemplo de uma linguagem fortemente tipada na qual / em dois números inteiros, não produz um número inteiro. E o Python 3 é outro.
sepp2k
1
A linguagem Haxe é fortemente tipada (embora inferida) e, no entanto, não possui divisão inteira, apenas float. Então lá vai você.
precisa saber é o seguinte
2

No Squeak Smalltalk, os /números inteiros criam objetos Fraction. Portanto, embora isso não seja o mesmo que divisão de flutuação, ainda (1/6)*6retorna 1.

Cefalópode
fonte
Em todos os derivados Smalltalk-80 (ou seja, quase todos os Smalltalks). O âmbar é uma das exceções contemporâneas (que é compreensível, sendo compilada em JavaScript).
Herby
2

Sim, acabei de verificar minha TI-99 / 4A incorporada no TI BASIC . Como trata todas as expressões numéricas como ponto flutuante, a operação de divisão também é ponto flutuante.

 TI BASIC READY
>PRINT 1/6
  .1666666667

>
Jesse C. Slicer
fonte
2

VB ( VB.Net , VB6 , VBA ...)

O operador de divisão inteira é \

MarkJ
fonte
2

MATLAB. Literais numéricos são duplos por padrão.

>> 1/6
ans =
    0.1667
Dima
fonte
2

Clojure usa frações por padrão. Não é o mesmo que 1.0 / 6.0, mas você pode convertê-lo com floatou doublequando precisar.

user=> (/ 1 6)
1/6
user=> (* (/ 1 6) 2)
1/3
user=> (pos? (/ 1 6)) ; Is 1/6 > 0?
true
user=> (float (/ 1 6))
0.16666667
defhlt
fonte
1

Surpreendentemente, parece funcionar corretamente no Windows PowerShell (versão 3) .

PS C:\> 1.0 / 6.0
0.166666666666667

PS C:\> 1/6
0.166666666666667

Também parece funcionar no Python 3, como mencionado no sepp2k. Os outros dois idiomas que eu tenho prontamente disponíveis no REPL, Scala e Ruby, ambos fazem divisão inteira e produzem 0.

KChaloux
fonte
0

A linguagem Rexx sempre produz uma resposta aritmeticamente correta. Por exemplo: 5/2 = 2,5. Rexx é uma ótima linguagem que não foi utilizada o suficiente. Em teoria, quando um compilador não pode determinar o que você deseja, é melhor fazer a matemática correta; no entanto, isso pode não ser eficiente. Rexx também fornece o operador //.

NoChance
fonte