Por que não há operador avançado em Java / C ++?

Embora exista tal operador – ** em Python, eu estava me perguntando por que Java e C ++ não têm um também.

É fácil fazer um para classes que você define em C ++ com sobrecarga de operador (e eu acredito que tal coisa seja possível também em Java), mas quando falamos sobre tipos primitivos como int, double e assim por diante, você “terá que usar a função de biblioteca como Math.power (e geralmente terá que converter ambos para duplicar).

Então – por que não definir tal operador para tipos primitivos?

Comentários

  • Em C ++, não podemos criar nossos próprios operadores. Você só pode sobrecarregar os operadores existentes.
  • @Mahesh, então posso criar minha própria classe Number e sobrecarregar o operador ^ para ser uma potência. Isso realmente não importa.
  • @RanZilber: É importante porque a precedência do operador ^ não corresponde à precedência de exponenciação. Considere a expressão a + b ^ c. Em matemática, a exponenciação é realizada primeiro (b ^ c), então a potência resultante é adicionada a a. Em C ++, a adição é realizada primeiro (a + b), em seguida, o operador ^ é realizado com c. Portanto, mesmo se você implementou o operador ^ para significar exponenciação, a precedência surpreenderá a todos.
  • @RamZilber – ^ é um XOR em C ++. É aconselhável que o operador sobrecarregado não faça diferente do que um tipo de dados primitivo faz ao usá-lo.
  • @RanZilber: Porque ‘ não é nada intuitivo de usar qualquer um dos operadores que você menciona para significar exponenciação. Eu questionaria seriamente a competência de qualquer programador C ++ que sobrecarrega o operador ++ ou o operador ! et. al. para significar exponentação. Mas você pode ‘ t de qualquer maneira, porque os operadores sobre os quais você fala aceitam apenas um argumento; a exponenciação requer dois argumentos.

Resposta

De um modo geral, os operadores primitivos em C (e por extensão C ++) são projetados para serem implementados por hardware simples em aproximadamente uma única instrução. Algo como a exponenciação geralmente requer suporte de software; portanto, não está lá por padrão.

Além disso, é fornecido pela biblioteca padrão da linguagem na forma de std::pow.

Finalmente, fazer isso para tipos de dados inteiros não faria muito sentido, porque a maioria, mesmo os pequenos valores de exponenciação estouram o intervalo necessário para int, que é até 65.535. Claro, você poderia fazer isso para duplos e flutuantes, mas não ints, mas por que tornar a linguagem inconsistente para um recurso raramente usado?

Comentários

  • Embora eu concorde com a maior parte disso, o fato de que o módulo operador não pode ser usado em tipos de ponto flutuante é inconsistente para tipos de dados primitivos, mas isso provavelmente não seria uma única instrução em qualquer hardware que eu imagino ser predominante agora.
  • @Sion: pelo menos em x86, o módulo é uma única instrução. (DIV faz a divisão e o módulo) Você ‘ me colocou no ponto de consistência.
  • @Billy ONeal: modo de ponto flutuante lus em uma única instrução? Eu não ‘ não me preocupei com a assembléia para saber por mim mesmo. Se esse ‘ for o caso, o operador de módulo deve ser aplicável aos tipos de ponto flutuante.
  • @DonalFellows: FORTRAN tinha o operador de exponenciação muito antes de ter qualquer coisa semelhante a suporte bignum.
  • @DonalFellows: Um operador de potência não é ‘ t tão útil com inteiros quanto com flutuadores, mas para potências pequenas (especialmente quadradas) poderia definitivamente tem seus usos. Pessoalmente, gosto da abordagem de fazer operadores de letras (como Pascal faz com div ou FORTRAN com .EQ.); dependendo das regras de espaço em branco do idioma, pode ser possível ter um número arbitrário de operadores sem exigir que sejam palavras reservadas.

Resposta

Esta pergunta é respondível para C ++: Stroustrup,” Design and Evolution of C ++ “discute isso na seção 11.6.1, pp. 247-250.

Havia objeções gerais para adicionar um novo operador. Isso aumentaria a já complicada tabela de precedência. Os membros do grupo de trabalho pensaram que seria apenas uma pequena conveniência em ter uma função e queriam ser capazes de substituir suas próprias funções às vezes.

Não havia nenhum bom candidato para operador.^ é ou exclusivo, e ^^ gerava confusão por causa da relação entre & e | e && e ||. ! não era adequado, pois haveria a tendência natural de escrever != para exponenciação de um valor existente, e isso já foi obtido. O melhor disponível pode ter sido *^, que aparentemente ninguém gostou muito.

Stroustrup considerou ** novamente, mas já tem um significado em C: a**p é a vezes o que p aponta para, e char ** c; declara c como um ponteiro para um ponteiro para char. Apresentando ** como um token que significa “declaração de um ponteiro para um ponteiro para”, “vezes o que a próxima coisa aponta para” (se for “um ponteiro) ou” exponenciação “(se seguido por um número) causou problemas de precedência. a/b**p teria que ser analisado como a/(b**p) se p fosse um número, mas (a/b) * *p se p fosse um ponteiro, então isso teria que ser resolvido no analisador.

Em outras palavras, teria sido possível, mas teria complicado a tabela de precedência e o analisador, e ambos já são muito complicados.

Não conheço a história do Java; tudo o que eu poderia fazer seria especular. Quanto ao C, onde começou, todos os operadores C são facilmente traduzidos em código assembly, em parte para simplificar o compilador e em parte para evitar ocultar a funcionalidade demorada em operadores simples (o fato de que operator+() e outros podem esconder grande complexidade e desempenho, foi uma das primeiras reclamações sobre C ++.

Comentários

  • Boa resposta. Acho que o Java tentou simplificar o C nesse aspecto, então ninguém quis adicionar um novo operador. Que ‘ é uma pena que ninguém tenha me perguntado, eu certamente teria gostado de *^. : D
  • C foi construído para fazer formatação de texto. O Fortran foi construído para fazer matemática e tinha matemática complexa, de poder e de matriz 20 anos antes.
  • @Martin Beckett: Você pode encontrar evidências de que C foi construído para formatação de texto? Parece-me uma linguagem muito desajeitada para isso, e o que eu ‘ li sobre a origem do C diz que ele foi projetado para programação de sistema principalmente para Unix.
  • @DavidThornley – Ele foi projetado para escrever no Unix, mas todos os primeiros usos do Unix parecem ter sido formatação de texto, e para isso ‘ o tempo que ele tem uma extensa string e eu / o biblioteca.
  • +1: O significado existente para a**p é o assassino. (Os hacks para contornar esse problema … Brr!)

Resposta

Eu suspeito é porque cada operador que você introduz aumenta a complexidade do idioma. A barreira para a entrada é, portanto, muito alta. Eu uso exponenciação muito, muito raramente – e estou mais do que feliz em usar uma chamada de método para fazer então.

Comentários

  • Cada recurso começa com -100 pontos.
  • Eu ‘ d uso x**2 e x**3 raramente . E uma implementação mágica que o compilador conhece e otimiza para os casos simples seria boa.
  • @CodeInChaos: No entanto, x * x e x * x * x aren ‘ t maus substitutos para o quadrado e o cubo.
  • @David você pode ‘ t simplesmente escreva x*x se x for uma expressão. Na melhor das hipóteses, o código torna-se pesado e, na pior, mais lento ou até errado. Portanto, você ‘ d precisa definir suas próprias funções Square e Cube. E mesmo assim o código seria mais feio do que usar ** como operador avançado.
  • @David, preciso colocar parênteses sim, mas não ‘ não preciso repetir a expressão várias vezes e incha o código-fonte. O que reduz muito a legibilidade. E a eliminação da subexpressão comum só é possível se o compilador puder garantir que a expressão esteja livre de efeitos colaterais. E pelo menos .net jitter não é ‘ t muito inteligente a esse respeito.

Resposta

A linguagem Java e os designers da biblioteca central decidiram relegar a maioria das operações matemáticas à classe Matemática . Consulte Math.pow () .

Por quê? Flexibilidade para priorizar o desempenho em relação à precisão bit a bit.Seria contra o resto das especificações da linguagem dizer que o comportamento dos operadores matemáticos integrados pode variar de plataforma para plataforma, enquanto a classe Math afirma especificamente que o comportamento potencialmente sacrifica a precisão para o desempenho, portanto, cuidado com o comprador:

Ao contrário de alguns dos métodos numéricos da classe StrictMath , todas as implementações das funções equivalentes da classe O Math não está definido para retornar os mesmos resultados bit a bit. Este relaxamento permite implementações de melhor desempenho onde a reprodutibilidade estrita não é necessária.

Resposta

A exponenciação fez parte do Fortran desde o início porque era voltada diretamente para a programação científica. Engenheiros e físicos o usam com frequência em simulações, porque as relações de lei de potência são comuns na física.

Python também tem uma forte presença na computação científica (por exemplo, NumPy e SciPy). Isso, junto com seu operador de exponenciação, sugere que ele era voltado para a programação científica também.

C, Java e C # têm raízes na programação de sistema. Talvez essa seja uma influência que manteve a exponenciação fora do grupo de operadores suportados.

Apenas uma teoria.

Resposta

Operadores definidos em C apenas para operações aritméticas comuns acessíveis com a ALU. Seu objetivo principal era criar uma interface legível para o código Assembly.

C ++ não alterou nenhum comportamento do operador porque desejava todos a base de código escrita em C para ser compatível.

Java fez o mesmo porque não queria intimidar os programadores C ++ existentes.

Comentários

  • Quando C foi criado, a multiplicação e a divisão não eram raro em falta de hardware e tinham que ser implementadas em software. Mesmo assim, C tem operadores de multiplicação e divisão.
  • @siride: Até onde sei, o PDP-7, o primeiro computador a rodar Unix, tinha multiplicação e divisão de hardware por meio de seu EAE. Consulte: bitsavers.org/pdf/dec/pdp7/F-75_PDP-7userHbk_Jun65.pdf

Resposta

Bem, porque cada operador que faria sentido para um poder já está em uso. ^ é XOR e ** define um ponteiro para um ponteiro. Em vez disso, eles têm apenas uma função que faz a mesma coisa. (como pow ())

Comentários

  • @RTS – Um desenvolvedor de linguagem está realmente procurando mais sentido do que eficiência?
  • Um bom desenvolvedor de uma linguagem de programação olha para ambos. Não posso ‘ não dizer nada sobre java. Mas em c ++ a função pow () é calculada em tempo de compilação. E é tão eficiente quanto os operadores regulares.
  • @RTS: A função pow() realiza seus cálculos em tempo de execução, a menos que você tenha um compilador que possa fazer dobramento constante para pow(), o que duvido muito. (Alguns compiladores oferecem a opção de usar intrínsecos do processador para realizar o cálculo, no entanto.)
  • @In silico Eu não ‘ significa que ele calcula o final valor, eu quis dizer que os compiladores otimizarão a chamada de função, então você tem apenas a equação bruta.
  • @josefx: Claro ‘ é um bom motivo. Um único * é um token léxico, seja ‘ usado para indireção ou multiplicação. Uma ** significando exponenciação seria um ou dois tokens lexicais, e você realmente não ‘ quer que seu lexer tenha que atingir o símbolo tabela a ser tokenizada.

Resposta

O fato é que os operadores aritméticos são apenas atalhos de funções. (Quase) Tudo que você faz com eles pode ser feito com uma função. Exemplo:

c = a + b; // equals c.set(a.add(b)); // or as free functions set(c, add(a,b)); 

É apenas mais prolixo, então não vejo nada de errado em usar funções para realizar “poder de”.

Resposta

Adição / subtração / negação e multiplicação / divisão são operadores matemáticos básicos. Se você transformasse o poder em um operador, onde pararia? Raiz quadrada operador? Operador N-root? Operador logaritmo?

Não posso falar pelos seus criadores, mas posso dizer que acho que seria complicado e não ortogonal ter tais operadores na linguagem. número de caracteres não alfanuméricos / espaços em branco restantes no teclado é bastante limitado. Como é, é estranho que haja um operador de módulo em C ++.

Comentários

  • +1 – Não ‘ não vejo por que ter mod como operador é estranho. ‘ s geralmente uma única instrução. É ‘ uma operação primária em inteiros. É ‘ s mais usado em toda a ciência da computação.(Implementar coisas como buffers limitados sem mod iria feder)
  • @Billy ONeal: Estranho por causa da inconsistência entre ser capaz de usar com tipos inteiros e tipos de ponto flutuante . No entanto, é absolutamente útil e eu não ‘ sonharia em removê-lo. Só peculiar é tudo.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *