Tipo float e double

23 respostas
marciosouzajunior

Porque o java não aceita a seguinte declaração??
float f = 1.3;

23 Respostas

remixlara

Porque o valor 1.3 é por padrão double em java. Pra que você possa fazer essa atribuição é necessário fazer o casting que pode ser de duas formas:

float f = (float)1.3;

ou

float f = 1.3F;

que funcionam da mesma forma. essa atribuição funcionaria se fosse feito da seguinte forma:

double f = 1.3;
rodrigo.guri

ops:

rodrigo.guri

aproveitando a pergunta
ontem estava mexendo com parametros e reparei uma coisa se tenho um metodo

double saldo; Conta(){ atualiza(saldo) }
e pegar na funcao um float ou mesmo um int
ele nao deixa, acredito que porque ocorre perda de dados de precisão, depreciamento, nem sei se existe isso
do double para float, tipo este aqui que deu errado pegando float de double

float atualiza(float depositoInicial) { depositoInicial = s.nextFloat(); //eu sei que deve ser double para valores,mas so para aprender coloquei outro tipo no caso float!! atualizaSaldo += depositoInicial; return atualizaSaldo; //quero que seja float //o metodo atualiza nao deve ter o atributo saldo como float? }
a variavel double la em cima,

  1. é o valor que a função irá usar?
  2. ou o valor que a função vai retornar?
    neste caso ela retorna um float atualizaSaldo e passa saldo que é double
quikkoo

ñ é aceita essa passagem de parametro pelo mesmo motivo que ñ aceita a atribuição, ao transformar um tipo double em float há perda de precisão, entao o compilador exige q vc faça isso explicitamente com um cast, algo como “prove pra mim que vc sabe oq está fazendo”

e sobre sua pergunta, ‘saldo’ é passado como parametro, entao o valor em ‘saldo’ é atribuido a ‘depositoInicial’

marciosouzajunior

O valor que a função irá usar é o saldo da primeira linha, mas seria interessante passar por parâmetro:

void Conta(double saldo){ atualiza(saldo); }

Pra retorna um valor vc deve colocar o tipo do retorno entre o modificador e nome da função na declaração, e em pelo menos 1 lugar deve ter um return dentro da função:

double Conta(double saldo){ return atualiza(saldo); //aqui a função atualiza deve retornar o mesmo tipo pra dar certo //eu não testei o código }

remixlara

Em java existe as classes utilitárias conhecidas com wrapper e elas servem pra fazer operações básicas como essa de conversão. por exemplo.

para um double existe uma classe wrapper chamada Double que possui uma operação de conversão de double pra float. Por exemplo:

double saldo = 1.3;

Double d = new Double(saldo);

float depositoInicial = d.floatValue();

cada tipo primitivo possui sua classe wrapper que possuem diversas opções de conversão.

vlw

ViniGodoy

[quote=remixlara]Porque o valor 1.3 é por padrão double em java. Pra que você possa fazer essa atribuição é necessário fazer o casting que pode ser de duas formas:

float f = 1.3F;

Essa operação não é um casting, mas uma especificação do tipo do literal.
Com essa declaração você diz que aquele 1.3 é um float. O compilador já criará do tipo float e não haverá perda de informação. Alguns castings (como o de double para float) exigem mais processamento do que só a reinterpretação do dado, por isso, essa forma é preferível ao casting direto.

Sem falar que é mais fácil de escrever e polui menos o código. :slight_smile:

remixlara

boa… não tinha me atentado a isso. vc tem razão.

ViniGodoy

Os wrappers fazem dois tipos de conversão:

  1. Conversões com String;
  2. Conversões para int, em seu formato binário bruto.

Você não precisará nunca criar um wrapper com new para fazer conversões:

float valor = Float.parseFloat("1.13"); int bits = Float.floatToIntBits(1.13f);

Para converter double num float, sempre se faz através de cast:

double umDouble = 3.1415; float x = (float) umDouble;

O que você fez é uma enorme besteira. Você criou um objeto temporário. Atribuiu o valor passado por parâmetro a um double, que é um campo privado desse objeto. Depois chamou o método floatValue() que irá fazer o cast. É muito mais simples, rápido e fácil fazer o cast diretamente.

Os wrappers tem uma única finalidade: Representar o tipo primitivo quando um objeto for necessário. É o caso, por exemplo, em listas e sets, que só trabalham com objetos e não com tipos primitivos.

List<Double> lista = new ArrayList<Double>(); lista.add(Double.valueOf(1.13)); lista.add(Double.valueOf(2.14)); lista.add(Double.valueOf(3.1415));

No C++ e C# é possível criar listas de tipos primitivos:

std::vector<int> lista = new std::vector<int>(); //Valido em C++ IList<int> lista = new List<int>(); //Válido em C#

rodrigo.guri

essas conversões com cast eu ja conhecia
uso em c++, mas achei estranho duas colocações

que nem o colega disse
1)‘saldo’ é passado como parametro, entao o valor em ‘saldo’ é atribuido a ‘depositoInicial’
pelo que aprendi se colocar private double saldo na declaração de variaveis
e colocar double saldo no metodo que utiliza, ou seja o mesmo nome para as variaveis
elas são variaveis ou atributos diferentes, com valores diferentes
São diferentes, ou depois do metodo executar ficam iguais?

2)e o casso de perda de precisão, existe?
porque se eu pegar um passar um char,int,short ou float
e em algum método pegar um double ex.

private int x; conta{ atualiza(x) } atualiza(double saldo)

este método é aceito e sem usar cast
(ai minha mãe :frowning: )

ViniGodoy

rodrigo.guri:
que nem o colega disse
1)‘saldo’ é passado como parametro, entao o valor em ‘saldo’ é atribuido a ‘depositoInicial’
pelo que aprendi se colocar private double saldo na declaração de variaveis
e colocar double saldo no metodo que utiliza, ou seja o mesmo nome para as variaveis
elas são variaveis ou atributos diferentes, com valores diferentes
São diferentes, ou depois do metodo executar ficam iguais?

São diferentes. Dentro do método haverá a variável saldo (do método) e a this.saldo (da classe).
Elas não ficarão iguais.

rodrigo.guri:
2)e o caso de perda de precisão, existe?
porque se eu pegar um passar um char,int,short ou float
e em algum método pegar um double ex.

O double é uma variável de 64bits, a maior do Java. Muito difícil perder precisão com ele. Tão difícil que o Java não exige cast para double.

ribclauport

Ressucitando o post para trazer a ele um conteúdo e também um pedido de horizonte para o Viny no tocante ao estudo deste fenômeno desagradável,
Estuando para certificação me deparei com o código abaixo:

public class Conversion
{
   public static void main(String[] args)
   {
     int i = [telefone removido];
     float f = i;
     System.out.println(i - (int)f);
   }
}
e na realidade isso não imprime 0, pois tem a seguinte explicação:

Actually it prints -46. This is because the information was lost during the conversion from type int to type float as values of type float are not precise to nine significant digits.

Bom, passei no java ranch, e fiquei mais assustado ainda pois a explicação para tais fenomênos vem da "IEEE 754 floating-point encoding ", e nesse post vi uma explicação, mais não entendi o que acontece na dúvida abaixo:

post: http://www.coderanch.com/t/266307/java-programmer-SCJP/certification/Changes-out-put

Hi All,
There are two examples related float precision. The only difference is the value of int i differs and both the example gives different results. 

Please explain why?

Example 1:

int i = [telefone removido]; 

float f = i;

int x = (int)f;

System.out.println(i == x); //Prints false


Example 2:
int i = Integer.MAX_VALUE;

float f = i;

int x = (int)f;

System.out.println(i == x); //Prints true

explicação do rapaiz la ultra mega informado:

posted quinta-feira, 15 de novembro de 2007 11:52 0 You'll have to know something about IEEE 754 floating-point encoding to really understand this issue completely.

But briefly, the most important point here is that a float value cannot represent every int value precisely. floats are 32 bits long, and ints are also 32 bits long--but some of the 32 bits in the float are used to store the exponent (i.e. the "power"), leaving the float with only 23 bits to store the number's actual significant digits (called the significand). One more significant digit will automatically be assumed for most numbers (see the IEEE 754 spec). Therefore, once your int value is large enough that it requires more than 24 significant binary digits to represent, you're very likely to lose precision.

The two numbers you used in your tests ([telefone removido] and Integer.MAX_VALUE) are examples of such large numbers. As a result, when you cast them to a float, the JVM will choose the closest representable float value to your int value.

For [telefone removido], the closest float value is [telefone removido]. Other int values "close" to [telefone removido] will also be mapped to a float value of [telefone removido]. (To be precise, all ints from [telefone removido] to [telefone removido] will be mapped to this value.) This loss of precision causes the non-equality you observed when you cast the float back to an int.

Integer.MAX_VALUE ([telefone removido]) is a more interesting case. This will get mapped to a float value of 2^31, or [telefone removido]. (All numbers from [telefone removido] to [telefone removido] will be mapped to this value.) However, when you cast this float value back to an int, this is larger than the maximum value of an int, so the JVM maps it back to Integer.MAX_VALUE. Hence your equality test prints "true".

Note that your code will print "true" for int values that are exactly representable with a float. As already mentioned, [telefone removido] is one such number. The next smaller one is [telefone removido], and the next larger one is [telefone removido].

Also, you won't get any loss of precision converting an int to a double, because a double uses 52 bits for its significand. However, you'll run into the same problem if you convert a long to a double.

Realmente as partes que não entendi foram estas:

Integer.MAX_VALUE ([telefone removido]) is a more interesting case. This will get mapped to a float value of 2^31, or [telefone removido]. (All numbers from [telefone removido] to [telefone removido] will be mapped to this value.) However, when you cast this float value back to an int, this is larger than the maximum value of an int, so the JVM maps it back to Integer.MAX_VALUE. Hence your equality test prints "true".

e também

Also, you won't get any loss of precision converting an int to a double, because a double uses 52 bits for its significand. However, you'll run into the same problem if you convert a long to a double

Tudo isso ficou muito confuso e acho que nunca mais vou conseguir usar tipos diferentes... pois sempre vou achar que tudo perde precisão... se puder Viny me dizer, se vou ter que ler toda a IEEE 754 floating-point encoding, ou como fazer para enter o conteúdo dessa discussão(o que ler, se tem livro que trata disso...) agradeço.

ViniGodoy

Primeiro passo, leia esse post onde eu explico como funciona o ponto flutuante (sem entrar nos detalhes da implementação do IEEE):
http://www.guj.com.br/java/261493-ponto-flutuante-e-ponto-fixo#1365723

Você só precisa entender que para um mesmo número de bits, os tipos de ponto flutuante sempre conseguem representar valores menores que os inteiros.
Eles tem menor precisão.

float tem 32 bits, ints também, portanto, haverá perdas de precisão ao converter int para float.
double tem 64 bits, como o long, portanto, haverá perdas de precisão ao converter de long para double.

Entretanto, a perda só ocorre em valores muito grandes.
Se você estiver trabalhando com valores de até 8 casas decimais, dificilmente terá problemas.

Números de ponto flutuante também são naturalmente imprecisos. Esse outro post explica o porque dessa imprecisão natural:

ribclauport

Viny, muito obrigado pela sua ajuda, vou fazer exatamente como você indicou, gostaria de saber por exemplo como eu faria a validação, por exemplo se vier um numero com
oito digitos então emito uma mensagem problemas com o casting…sendo assim vou ler o post, pois desta forma preciso saber realmente em que ponto vai acontecer isso…

Novamente muito obrigado pela sua atenção.

ViniGodoy

Em muitas aplicações, um número tão grande já vai ser restringido na interface (se for um valor financeiro, estamos falando em bilhões).
Para muita precisão, use o BigDecimal:


http://docs.oracle.com/javase/1.5.0/docs/api/java/math/BigDecimal.html

ribclauport

Legal, nem tinha imaginado isso, estou realmente afundado no interesse neste assunto, e vou ler todos os posts que você indicou e mais alguns se for preciso…
Viny estou lendo o segundo post, e gostaria de tirar uma dúvida… na sua explicação tem a seguinte afirmação:

2 = 10
0,5 = 1
2,5 = 10.1

uma dúvida, no caso na segunda linha o quer dizer? seria que 0,5 é o mesmo que 0,1X2^-1 que é o mesmo que 0,1 em binário, e sendo assim voce colocou ali o 1 que é o que será depois da vírgula?
Aproveitando a deixa vi que na calculadora do windows não consigo colocar o valor por exemplo 2,5, para converter em binário para assim corrigir minhas conversões…

Desculpa incomodar tanto…

ViniGodoy

Ops… a linha tava errada. O certo é
0,5 = 0.1

Já corrigi no post original também.

rodrigo.guri

opa topico de 2010 em questão, quando eu fiz a pergunta nem sabia oque era parâmetros, hoje estou melhorzinho, rs :lol:
nunca deixem de responder perguntas basicas como estas, incentivam quem esta começando a continuar no java.

ribclauport

Viny, muito obrigado pela atenção.

ribclauport

Viny, por favor ja tentei ler vários artigos, para obter creio que a resposta para a ultima dúvida diante de tudo que ja li, e não estou conseguindo entender uma afirmação matemática, que encontrei em todas as referências a respeito de maior número na representação simples do padrão IEE754

veja abaixo um trecho que li no slide 47 deste link

http://www.dsc.ufcg.edu.br/~cnum/modulos/Modulo2/conceitosBasicos.ppt

Bom, eu entendi tudo a respeito da mantissa, do sinal, do expoente polarizado… na verdade o que eu não estou entendo é a parte que multiplica o expoente…

2^(127) --> isso aqui eu entendi que é maior expoente, e então multiplica a parte da mantissa… que é justamente o que eu não estou entendendo, ou seja de onde foi tirado o dois que que diminui o dois elevado a menos 23, ou seja de onde foi tirado esse negócio aqui abaixo:

(2-(2^-23)

Se puder me ajudar a entender essa parte eu agradeço, lembrando que toda a parte de polarização de expoentes, bit de sinal, bit da mantissa escondido (no caso 1 para representação binária) eu entendi, só realmente não estou entendendo esta expressão para o maior número, de onde foi tirada aquela subtração de dois ali…

ribclauport

Bom, ainda aqui estudando o caso acho que na verdade é uma dúvida básica de representação binária…gostaria de saber por favor Viny por que
o número binário abaixo é representado com aquela subtração, ou seja por que subtrae-se (2) de (2 elevado a -4), no slide 37 da mesma referência citada acima, ele especifica também…

Maior número positivo é (lembre do bit escondido)
0 110 1111 = + 2^3 x 1,1111 = 2^3 x (2- 2^-4 ) = 1111,1 = 15,5 decimal

Isso quer dizer a afirmação abaixo?

1,1111 = 2- (2^(-4))

consigo apenas enchergar

1 + 0.1111

Ou seja vejo sempre uma soma e não uma subtração, coloquei isso aqui apenas para complementar a dúvida acima. Obrigado.

ViniGodoy

Se dá por causa do bit escondido. Ele sempre representa 1 antes da vírgula, que em binário corresponde ao valor 2.
Ele é implícito na representação, mas você deve considera-lo ao fazer os cálculos.

Eu geralmente não explico o formato do IEEE, pois ele é cheio de detalhes para poupar bits e maximizar a precisão numérica. Entretanto, o conceito básico do porque a imprecisão ocorre independe desses artifícios.

ribclauport

post errado.

Criado 23 de maio de 2010
Ultima resposta 22 de abr. de 2012
Respostas 23
Participantes 6