5 svar
212 visningar
solaris är nöjd med hjälpen
solaris 238 – Fd. Medlem
Postad: 28 dec 2018 15:43 Redigerad: 28 dec 2018 15:43

double blir 5.551115123125783E-17 eller 0.0

Hej jag undrar varför a inte blir 0.0 men b blir det. 

double a = 1.0;

double b = 1.0;

a = a - 0.7 -0.3;

b = b - 0.6 -0.4;

Jag testade och ändra b = b - 0.1 - 0.9 och det blev också 0.0 så jag antar att det har något med det att göra. men jag förstår inte riktigt varför det blev som det blev. 

Taylor 680
Postad: 28 dec 2018 15:53

Detta är väl känt och ligger i sakens natur. Inte främst i Javas natur utan i subtraktions natur med oprecist representerade tal. 

 

https://en.wikipedia.org/wiki/Double-precision_floating-point_format

 

Precisionen är ungefär 16 signifikanta siffror ... dvs en avvikelse med "E-17" måste tolereras.

AlvinB 4014
Postad: 28 dec 2018 16:32

Om man vill undvika avrundningsfelen man får med flyttal kan man använda sig av klassen 'BigDecimal':

https://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html

Notera dock att double är mycket snabbare än BigDecimal, så använd bara detta om du verkligen behöver exakt precision (t.ex. om man programmerar något med valuta).

Taylor 680
Postad: 28 dec 2018 16:43 Redigerad: 28 dec 2018 17:03

Den praktiska lösningen blir väl att avrunda lite resultatet innan det skrivs ut, nämligen till mindre än 16 signifikanta siffror.

AlvinB 4014
Postad: 28 dec 2018 17:49
Taylor skrev:

Den praktiska lösningen blir väl att avrunda lite resultatet innan det skrivs ut, nämligen till mindre än 16 signifikanta siffror.

Nja, det håller jag inte med om. Om det nu är viktigt att ha precision på sina värden rekommenderar jag faktiskt att man använder BigDecimal. Det är betydligt enklare än att hålla på att avrunda stup i kvarten. Dessutom kan man efter tillräckligt många avrundningar få synliga avrundningsfel. Det finns mycket att läsa om detta här:

https://stackoverflow.com/questions/42871564/a-realistic-example-where-using-bigdecimal-for-currency-is-strictly-better-than

Laguna 28443
Postad: 28 dec 2018 19:59 Redigerad: 28 dec 2018 20:05

Det finns någon webbsida där man kan skriva in ett tal i decimalform och få se det i binärform enligt den vanligaste kodningsmetoden, bara för att se hur det blir binärt. Själva problemet orsakas av att det som är exakta tal när man skriver dem decimalt oftast inte är det i en annan bas, t.ex. två.

 

Den traditionella rekommendationen är att antingen inte jämföra flyttal alls, eller att alltid tillåta en viss marginal, t.ex. 10^-10. Om det inte är väldigt viktigt med hastigheten kan man använda någon exakt representation, med någon lämplig klass, som har nämnts ovan. Om hastigheten är viktig använder man double och håller reda på när man måste tänka på avrundningsproblemen. Är hastigheten mycket viktig använder man inte flyttal, utan bara heltal.

Edit: tillägg: det där "hålla reda på" är ett helt matematiskt fält och heter "numerisk analys". Ibland fortplantar sig de små felen kraftigt och förstör hela uträkningen om man gör på ett sätt, men inte om man gör på ett annat. När man löser ett linjärt ekvationssystem ska man t.ex. se till att man delar med så stora koefficienter som möjligt, det kallas pivotering.

Edit 2: tillägg: nu tänkte jag mest på fysikaliska beräkningar, men problemet finns också där om man ska representera enorma pengabelopp (miljarder) med noggrannhet ner till öret. Är man en bank duger det inte att avrunda.

Svara Avbryt
Close