float w C vs float w C#

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ć?

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-us/dotnet/api/system.single.tostring?view=netframework-4.7.2#System_Single_ToString_System_String_

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

0

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

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ę.

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.

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.

2

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

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).

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.

0

Wszystko na ideone odpalałem ;)

0

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

0

Skopiowałem, nie wiem czemu teraz jest inaczej.... może to zależy od śmieci w ramie :D ?

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