float w C vs float w C#

Odpowiedz Nowy wątek
2018-10-26 18:43
1

Tak sobie sprawdzałem, czy wynik float dla liczby podzielonej przez 2.0f będzie taki sam jak jak wynik float tej samej liczby pomnożonej przez 0.5f.
Najpierw wykonałem test w języku C#, ale przy wypisywaniu nie mogłem uzyskać wszystkich miejsc po przecinku!
Potem pomyślałem, że C jednak jest bardziej niskopoziomowy i w nim dam radę. No i mam ;)

C#: https://ideone.com/cmgLUY

using System;

public class Test
{
    public static void Main()
    {
        float a = 7.52321311545f;

        Console.WriteLine(a.ToString("N30"));
        Console.WriteLine((a / 2.0f).ToString("N30"));
        Console.WriteLine((a * 0.5f).ToString("N30"));
    }
}

Wynik C#:

7.523213000000000000000000000000
3.761606000000000000000000000000
3.761606000000000000000000000000

C: https://ideone.com/AJQetN

#include <stdio.h>

int main(void) {
    float a = 7.52321311545f;
    printf("%0.30f\n%0.30f\n%0.30f\n", a, a/2.0f, a * 0.5f);
    return 0;
}

Wynik C:

7.523212909698486328125000000000
3.761606454849243164062500000000
3.761606454849243164062500000000

W C# jest 6 miejsc po przecinku, a w C ok. 20 miejsc po przecinku. Dlaczego C# obcina floata, chociaż każę mu tego nie robić?

edytowany 2x, ostatnio: Spine, 2018-10-26 18:47

Pozostało 580 znaków

2018-10-26 19:33
2

By default, the return value only contains 7 digits of precision although a maximum of 9 digits is maintained internally. If the value of this instance has greater than 7 digits, ToString(String) returns PositiveInfinitySymbol or NegativeInfinitySymbol instead of the expected number. If you require more precision, specify format with the "G9" format specification, which always returns 9 digits of precision, or "R", which returns 7 digits if the number can be represented with that precision or 9 digits if the number can only be represented with maximum precision

źródło: https://docs.microsoft.com/en[...]System_Single_ToString_SystemString

Wygląda na to, że więcej nie wypiszesz bo, toString zwraca max. 9 znaków a resztę wypełnia zerami.

Pozostało 580 znaków

2018-10-26 20:06
0

Wciąż mało, ale dzięki za znalezienie wyjaśnienia ;)

Taką precyzję ma float. Ale zawsze możesz rzutować na double - kamil 2018-10-26 20:09

Pozostało 580 znaków

2018-10-26 20:08
5
       float a = 7.52321311545f;

Ta liczba ma więcej cyfr znaczących niż float jest w stanie pomieścić niezależnie od tego czy to C czy C#, więc na tym w sumie można zakończyć analizę.

Pozostało 580 znaków

2018-10-26 20:15
0

Ale ja właśnie chciałem też dostać te nieznaczące śmieci. A ilość miejsc po przecinku w przykładowej liczbie tak sobie po prostu rosła przy testowaniu. Wpisywałem byle co, żeby zobaczyć czy *0.5 będzie różne od /2.

edytowany 1x, ostatnio: Spine, 2018-10-26 20:16

Pozostało 580 znaków

2018-10-27 12:26
0

Ale ponad te 7 czy 9 cyfr będziesz dostawał właśnie śmieci, a ty tam oczekujesz konkretnych cyfr, czegoś czego float ci nie zapewnia.

Pozostało 580 znaków

2018-10-27 15:24
2

Spróbuj wypisywać floata szesnastkowo. Wtedy nie będzie wymówek o cyfrach znaczących :]


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.

Pozostało 580 znaków

2018-10-27 19:51
0

No i mamy wyniki.

https://ideone.com/5WauYd

using System;

public class Test
{
    public static void Main()
    {
        float a = 7.5232f;

        Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes(a)));
        Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes(a / 2.0f)));
        Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes(a * 0.5f)));
    }
}

https://ideone.com/G4SEEP

#include <stdio.h>
#include <string.h>

int main(void) {
    float a = 7.5232f;
    unsigned int ui;
    memcpy(&ui, &a, sizeof (ui));
    printf("%x \n", ui);

    a = 7.5232f;
    a = a / 2.0f;
    memcpy(&ui, &a, sizeof (ui));
    printf("%x \n", ui);

    a = 7.5232f;
    a = a * 0.5f;
    memcpy(&ui, &a, sizeof (ui));
    printf("%x \n", ui);

    return 0;
}

Wynik C#:

29-BE-F0-40
29-BE-70-40
29-BE-70-40

Wynik C:

40f0be0e 
4070be0e 
4070be0e 

Pewnie kolejność bajtów w jednym z wyników trzeba by odwrócić, ale liczba wychodzi prawie ta sama. 29 (pierwszy bajt c#) nie pasuje do 0e (ostatni bajt C). A może to kolejny dowód automatycznego zaokrąglania w C# ? (o ile konwersja jest poprawna).

edytowany 7x, ostatnio: Spine, 2018-10-27 19:54

Pozostało 580 znaków

2018-10-30 15:05
0

Gdzie kompilujesz? https://dotnetfiddle.net/VQIFHV daje

0E-BE-F0-40
7.5232

Za https://gregstoll.dyndns.org/~gregstoll/floattohex/ :

0x40f0be0e == 7.5232

a

0x40f0be29 == 7.52321

Podaj platformę, kompilator i wersję CLR.

Pozostało 580 znaków

2018-10-30 15:26
0

Wszystko na ideone odpalałem ;)

Pozostało 580 znaków

2018-10-30 15:28
0

To skąd wziąłeś 29, jeżeli ten link https://ideone.com/5WauYd (podany przez Ciebie) wypisuje 0E-BE-F0-40 ?

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0