Ir para o conteúdo
Gman9

Provar que não há perda de precisão de float para short

Mensagens Recomendadas

Gman9

Boas pessoal tenho este problema para resolver mas não sei bem por onde começar, alguma ideia?

Apresente a função is_short, que retorna true se e só se o valor recebido como argumento puder ser representado por um short sem perda de informação. Na implementação interna só podem ser utilizadas operações aritméticas e lógicas sobre inteiros. Qualquer operação de vírgula flutuante invalida o exercício.

bool is_short(float f);

desde já obrigado ;)

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

algoritmo para chegar à solução:

- obter o valor do expoente

- obter o valor da mantisa

- saber se aplicar o expoente à mantisa "resulta em algum valor extra"

mais do que isto é quase dar o código, isto porque isto é possivel fazer com uma única linha ou mesmo uma macro function


IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

Bom problema!!! Também não estou a ver como fazer isso, sendo um comum mortal! :P...

Lembro-me de ter feito algo mas não sei se tinha a ver com isto. Era por exemplo decompor um valor da seguinte forma:

1254 = 1000 + 200 + 50 + 4

Mas isto se calhar não tem nada a ver! Já não me recordo! E pelo que tenho visto na net, o valor do sinal, expoente e mantissa são assuntos mais complexos que o que o HappyHippiHippo está a fazer parecer!

Mas tentando ir pela algoritmo do HappyHippiHippo

Considerando por exemplo o valor 453.039

O valor do expoente é -3

O valor da mantissa é 0.039 (acho eu)

Estou certo até aqui?

Editado por PsySc0rpi0n

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

Considerando por exemplo o valor 453.039

O valor do expoente é -3

O valor da mantissa é 0.039 (acho eu)

Estou certo até aqui?

não.

como calcular o expoente:

453.039      / 2 = 226.5195
226.5195     / 2 = 113.25975
113.25975    / 2 = 56.629875
56.629875    / 2 = 28.3149375
28.3149375   / 2 = 14.15746875
14.15746875  / 2 = 7.078734375
7.078734375  / 2 = 3.5393671875
3.5393671875 / 2 = 1.76968359375

expoente = número de divisões + 127 = 8 + 127 = 135 = 10000111

como calcular a mantisa:

0.76968359375 * 2 = 1.5393671875
0.5393671875  * 2 = 1.078734375
0.078734375   * 2 = 0.15746875
0.15746875    * 2 = 0.3149375
0.3149375     * 2 = 0.629875
0.629875      * 2 = 1.25975
0.25975       * 2 = 0.5195
0.5195        * 2 = 1.039
0.039         * 2 = 0.078
0.078         * 2 = 0.156
0.156         * 2 = 0.312
0.312         * 2 = 0.624
0.624         * 2 = 1.248
0.248         * 2 = 0.496
0.496         * 2 = 0.992
0.992         * 2 = 1.984
0.984         * 2 = 1.968
0.968         * 2 = 1.936
0.936         * 2 = 1.872
0.872         * 2 = 1.744
0.744         * 2 = 1.488
0.488         * 2 = 0.976
0.976         * 2 = 1.952
0.952         * 2 = 1.904
0.904         * 2 = 1.808
...

mantisa = valores da parte inteira da sucessão de multiplicações = 11000101000010011111101 (o resto é descartado ... erro de percisão de um valor de virgula flutuante)

binário final:

01000011111000101000010011111101

agora, como resovler tudo em uma linha ? deixo isso para mais tarde :P (até porque a minha solução tem mais do que 350 caracteres, mas como é uma macro functions, não deixa de ser tudo uma linha)

Editado por HappyHippyHippo

IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

Então para o cálculo do expoente, temos que dividir por o valor em questão, 8 vezes, certo?

Para a mantissa não percebi...


Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

para o expoente é necessário dividir o valor até ter algo do género : 1.XXXXXXX

o número de vezes que é necessário dividir dá o valor do expoente (somado do bias)

para a mantissa, é necessário pegar na parte fracionária do resultado anterior e multiplicar constantemente por 2, à parte fracionária do resultado anterior.

depois é pegar na parte inteira das multiplicações e combinar/montar o binário.


IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

Então se quiser aproveitar os argumentos da consola, como é que usamos o argv[1] como um float??? Isto não é gravado em argv[] como uma string?

Ou seja, se eu fizer:

./float_num 453.039

o valor 453.039 fica em argv[1] mas como string, certo?

Como é que depois trabalhamos com esse valor como float?


Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

acho que o gman9 já teve tempo de pensar na resposta, ao qual eu só digo:

#define is_short(f)             ((((*(unsigned int*) &f) << 1) == 0) || (((((*(unsigned int*) &f) & 0x7fffff) << (9 + ((((*(unsigned int*) &f) >> 23) & 0xff) - 127))) == 0) && ((((((*(unsigned int*) &f) >> 23) & 0xff) - 127) < 15) || ((((*(unsigned int*) &f) >> 31) == 1) && (((((*(unsigned int*) &f) >> 23) & 0xff) - 127) == 15) && (((*(unsigned int*) &f) & 0x7fffff) == 0)))))

ps : sim, é tudo uma só instrução

Editado por HappyHippyHippo

IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

Para evitar por exemplo este input:

52.0a23

o que se pode fazer??


Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

estás a dizer que para dar erro caso tenha texto a mais como por exemplo o "a32" no teu caso ? se sim

podes fazer uma marosca muito engraçada:

/*
char check;
float c;
*/
float f;
char c;
switch (sscanf(argv[1], "%f%c", &f, &c))
{
 case 1:
   // correct
   break;
 case 2:
   // have extra characters
   break;
 default: // zero
   // error : unable to read the float
   break;
}

Editado por HappyHippyHippo

IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

Pois, esses detalhes acabm por fazer a diferença... E não se se percebi bem como é que o sscanf funciona!

Mas por exemplo vamos analisar.

Neste caso específico, e segundo me apercebo, o sscanf lê o 52.0 para o "f" e deverá ler o "a" para o "c". Mas esta formatação que fizeste já não funciona caso o user input seja a25.036...

Ou seja, o meu objectivo era evitar qualquer engano por parte do user! (Isto acaba por sair fora do contexto do post, mas...)


Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

Neste caso específico, e segundo me apercebo, o sscanf lê o 52.0 para o "f" e deverá ler o "a" para o "c". Mas esta formatação que fizeste já não funciona caso o user input seja a25.036...

funciona ... isso cai no default


IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

O sscanf também apanha os '\n' que estão no buffer??? É que não estou a conseguir fazer funcionar essa marosca!

#include <stdio.h>
#include <stdlib.h>

#define CLEAR_SCREEN puts("\x1b[H\x1b[2J")
#define CLEAR_INPUT while (getchar () != '\n') /*void*/
#define INPUT_ERROR -1 
#define INPUT_OK     0

int main (int argc, char** argv){
   short int check = INPUT_ERROR;
   float num, c;

   if (argc < 2){
       printf ("Usage: ./floatnum <number>\n");
       exit (0);
   }

   while (check == INPUT_ERROR){
       switch (sscanf (argv[1], "%f%c", &num, &c)){
           case 1:  check = INPUT_OK;
                    break;
           case 2:  check = INPUT_ERROR;
                    printf ("That is not a number! Try again!\n");
                    CLEAR_INPUT;
                    break;
           default: check = INPUT_ERROR;
                    printf ("Unkown Error! Try again!");
                    break;
       }
   }

   printf ("Number is: %.2f\n", num);

   return 0;
}

o sscanf está sempre a retornar 2 mesmo que eu insira um número correcto!

Editado por PsySc0rpi0n

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

não sei o que andas a testar, mas no código só tens o problema de que a variável c deveria ser um char


IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

não sei o que andas a testar, mas no código só tens o problema de que a variável c deveria ser um char

Eu pus float porque tu to teu code também puseste o "c" como float!


Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

Eu pus float porque tu to teu code também puseste o "c" como float!

epa .. o código foi feito de cabeça ... corrigido

Editado por HappyHippyHippo

IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

Ok...

Bom, testei o code mas ainda ssim há algo que não está a funcionar!

Se eu lançar o programa assim:

./floatnum 53.2a

ele detecta efectivamente que houve dois valores lidos. Mas se a seguir colocar um valor correcto, o programa continua a detectar 2 valores lidos!

Editado por PsySc0rpi0n

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Flinger

Debug$ ./tester 53.2
Number is: 53.20
Debug$ ./tester 53.2a
That is not a number! Try again!

Só se for o windows a fazer das suas :D

Editado por Flinger

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

Bom, parece que eu já estou a fazer asneira no code!!! Já estou a misturar argumentos enviados pelo terminal e dados pedidos pelo programa ao user!

Deixem-me cá refazer isto!

E não, deste lado não se usa Windows!

Editado por PsySc0rpi0n

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!

Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.

Entrar Agora

×

Aviso Sobre Cookies

Ao usar este site você aceita os nossos Termos de Uso e Política de Privacidade. Este site usa cookies para disponibilizar funcionalidades personalizadas. Para mais informações visite esta página.