Ir para conteúdo
Fórum Script Brasil
  • 0

Float para int sem cast


Diogo Fonseca

Pergunta

Ola pessoal, primeiro obrigado a quem responder.

Estou com duvidas neste exercicio e não consigo chegar a resposta.

O Exercicio é o seguinte:

Escreva a função float_with_int_cmp, que compara o valor da parte inteira de fvalue com o valor inteiro ivalue. A função devolve um valor positivo se a parte inteira de fvalue for maior que ivalue, um valor negativo se a parte inteira de fvalue for menor que ivalue ou zero se forem iguais. Na implementação da função só podem ser utilizadas operações aritméticas e lógicas sobre inteiros. Qualquer operação de vírgula flutuante invalida o exercício.

int float_with_int_cmp(float fvalue, int ivalue);

OBS: eu nao estou a conseguir percerber como funciona o Float e as suas mantissas.

O codigo seguinte funciona mas não posso fazer assim o exercicio, ou seja não posso fazer Cast nenhum:

 

 

#include <stdio.h>

int float_with_int_cmp (float fvalue, int ivalue);

int main (){
    printf("%d\n", float_with_int_cmp(2.5, 1));
    return 0;
}

int float_with_int_cmp (float fvalue, int ivalue){
    
    if((int)fvalue > ivalue)
        return 1;
    else if((int)fvalue <ivalue)
        return -1;
    
    return 0;
}

Tenho que utilizar os conceitos das imagens mas não entendo.

Obrigado desde já :)

IEEE-754-ENGLISH.jpg

Link para o comentário
Compartilhar em outros sites

3 respostass a esta questão

Posts Recomendados

  • 0

Esse exercício não é trivial.

 

Primeiro é preciso entender como números reais são armazenados em variáveis float:

Tendo um número real você primeiro converte para o modo binário, separando a parte inteira e a parte fracionária, converte cada uma respectivamente para a forma binária (para o nosso caso não é importante saber como a parte fracionárias é convertida para binário, mas se tiver interesse basta pesquisar).

Por exemplo, convertendo o número decimal 12.375 para binário fica:

(12.375)10 = (12)10 + (0.375)10 = (1100)2 + (0.011)2 = (1100.011)2

Temos em binário então isto:

1100.011 = 1100.011 * 20

O ponto flutuante do número deve então ser deslocado para a direita ou esquerda tal que o ponto (.) fique imediatamente após o primeiro bit mais a esquerda (mais significativo) que for igual  1 (ou seja queremos o número na forma de notação científica), e ajustar o expoente do multiplicador 2 correspondentemente. Ficando:

1100.011 * 20 = 1.100011 * 23

Nosso número é positivo então o bit 32 armazena 0.

Temos que o expoente é 3, mas os 8 bits que armazenam o expoente no float, guardam um número binário indo de 0 a 255, para que seja possível armazenar expoentes negativos devemos usar o ponto central desse intervalo (= 127) como sendo o expoente 0, logo somamos o 127 ao valor do nosso expoente para obter o número a ser armazenado nos 8 bits do expoente. Ou seja:

127 + 3 = (130)10 = (10000010)2

E por fim apenas a parte fracionária da mantissa (nesse caso .100011) é armazenada nos 23 bits restantes do float, de modo que o ponto (.) fictício ficaria a esquerda dos 23 bits e os dígitos binários da parte fracionária são armazenados começando no bit 23 e indo para a direita. (O 1 da parte inteira do número binário é omitido, e deve ser assumido novamente quando o processo é invertido.)

O resultado final então fica: 0-10000010-10001100000000000000000

Ou em hexadecimal: 41460000H

 

Ok, vou para por aqui por agora, mais tarde posto mais explicações, mas primeiro me diga se conseguiu entender. O que precisa ser feito é o processo inverso então é preciso entender isto (talvez você já consiga até pegar a ideia pra fazer o código).

Editado por isrnick
Link para o comentário
Compartilhar em outros sites

  • 0

Vamos lá...

 

Precisamos obter a parte inteira de um número armazenado em uma variável float...

Vamos usar o exemplo da imagem que você postou:

número = (-248.75)10 = (1-10000110-11110001100000000000000)bin = (C378C000)H

 

Pra obter apenas o bit do sinal é simples basta deslocar o número em binário de 31 bits para direita (>> 31) e só o bit do sinal sobrará, então basta checar:

- Se:  bit do sinal = 1 => sinal = -

- Se:  bit do sinal = 0 => sinal = +

Nesse caso:

bit do sinal = número >> 31 = (00000001)H = 1    logo,   sinal = -


Para obter um inteiro contendo apenas os 8 bits do expoente da variável float, podemos deslocar o binário do float de >> 23 para eliminar a parte da mantissa, e em seguida fazer a operação AND (&) com FFH = 1111 11112 para eliminar o bit do sinal. Mas lembre-se que esse inteiro terá valor entre 0 e 255, então precisamos subtrair 127 desse número para finalmente obter o valor expoente.

No nosso exemplo:

11000011 01111000 11000000 00000000 >> 23  = 00000000 00000000 00000001 10000110

00000000 00000000 00000001 10000110 & 0xFF = 00000000 00000000 00000000 10000110 = 134

expoente = 134 - 127 = 7

 

Agora para obter a fração da mantissa podemos fazer a operação AND do binário do float com 7FFFFFH (= binário com 1 em todos os 23 bits mais a direita), para eliminar os bits do sinal e do expoente. E então somar com 800000H (= binário com 1 apenas no bit 24) para recuperar bit da parte inteira da mantissa que havia sido omitida.

Ficando:
 

11000011 01111000 11000000 00000000 & 0x007FFFFF = 00000000 01111000 11000000 00000000

00000000 01111000 11000000 00000000 + 0x00800000 = 00000000 11111000 11000000 00000000

Lembrando que o ponto (.) da mantissa fica entre os bits 24 e 23, temos que:

mantissa = (1.111100011)2

 

Juntando tudo resulta que:

número = - (1.111100011 * 27)2

 

Se nós deslocarmos o ponto para zerar o expoente, fica:

número = - (11111000.11 * 20)2 = - [ (11111000)2 + (0.11)2 ] = - [ (248)10 + (0.75)10 ] = (-248.75)10

Obtendo o número decimal original.

 

Para fazer isso computacionalmente, assumimos que o ponto (.) está fixo na entre os bits 23 e 24, podemos deslocar o binário para esquerda do valor do expoente (<< expoente), assim obteremos o número na forma com o expoente zerado.

No nosso exemplo o expoente é igual a 7, então:

00000000 1.1111000 11000000 00000000 << 7 = 01111100 0.11000000 0000000 00000000

Agora temos as partes inteira e fracionária separadas do número na forma binária, a esquerda e a direita respectivamente do nosso ponto imaginário (ou seja, a esquerda do bit 23 está a parte inteira do número e direita (incluindo o próprio) está a parte fracionária).

 

Precisamos apenas da parte inteira nesse exercício, podemos então eliminar a parte fracionária deslocando o número binário de >> 23, e sobra só a parte inteira, que é o que nós queremos.

01111100 011000000 0000000 00000000 >> 23 = 0000000 0000000 0000000 11111000

Logo:

Parte inteira do número o sem sinal = (11111000)2 = (248)10

 

Mas observe que fizemos 2 deslocamentos em seguida em direções opostas no mesmo binário << 7 e >> 23, poderíamos então calcular o deslocamento total = 23 - 7 = 16 e fazer um único deslocamento >> 16.

00000000 11111000 11000000 00000000 >> 16 = 0000000 0000000 0000000 11111000

Ou, de forma geral, para obter apenas a parte inteira do número, basta deslocar o número binário de >> (23 - expoente).

 

Finalmente basta multiplicar o resultado por -1 ou +1 dependendo do valor do bit do sinal para obter a parte inteira do número que poderá ser comparada com o outro número inteiro no programa.

 

 

 

A lógica está aí, fora isso a única coisa que você precisa para fazer o programa é uma maneira para conseguir fazer operações lógicas com o número float em forma binária, já que se você tentar fazer diretamente com a variável float vai gerar um erro na compilação.

O que você precisa é obter o valor binário da variável float numa variável int. E para isso podemos usar um ponteiro do tipo unsigned int e armazenar nele a referência da variável float (com um cast para ponteiro do tipo unsigned int). Dessa maneira:
 

unsigned int *fvaluebin;
fvaluebin = (unsigned int *)&fvalue;

//Então algo assim não gera erro pois o 
//ponteiro é do tipo int:
*fvaluebin = *fvaluebin & 0xFFFFFFFF; 

 

Também é bom notar que a variável float só pode armazenar no números inteiros de máximo +/- 224 - 1 = 16777215 sem que haja perda de precisão, então esse é o maior número inteiro que pode ser comparado de forma confiável. Acima disso o float passa a trucar os dígitos menos significativos (na forma binária).

Editado por isrnick
Link para o comentário
Compartilhar em outros sites

Participe da discussão

Você pode postar agora e se registrar depois. Se você já tem uma conta, acesse agora para postar com sua conta.

Visitante
Responder esta pergunta...

×   Você colou conteúdo com formatação.   Remover formatação

  Apenas 75 emoticons são permitidos.

×   Seu link foi incorporado automaticamente.   Exibir como um link em vez disso

×   Seu conteúdo anterior foi restaurado.   Limpar Editor

×   Você não pode colar imagens diretamente. Carregar ou inserir imagens do URL.



  • Estatísticas dos Fóruns

    • Tópicos
      152,3k
    • Posts
      652,3k
×
×
  • Criar Novo...