Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[C#] Vreemd probleem met Math.Sin

Pagina: 1
Acties:
  • 782 views sinds 30-01-2008
  • Reageer

  • Gurbe de n00b
  • Registratie: Juni 2003
  • Laatst online: 08-02-2024
Hallo Mensen,

Ik zit nu echt met een heel vreemd probleem waar ik me nu al een tijd op zit kapot te staren.

Ik moet even een functie maken voor een cirkel.
Dus ik even mijn kennis wat opgefrist over de Sinus, Cosinus en de Tangens functies, maar het wou maar niet lukken. Even een teststukje geschreven en hij gaf niet echt de antwoorden die ik wou.

C#:
1
2
3
4
5
6
7
// Als input 1 radiaal 
Console.WriteLine(Math.Cos(Math.PI)); // -1 => Dit is correct
Console.WriteLine(Math.Sin(Math.PI)); // 1.22460635382238E-16 => Die moet 0 zijn. Toch?

// Als input gewoon 0
Console.WriteLine(Math.Cos(0)); // 1 => Dit is correct
Console.WriteLine(Math.Sin(0)); // 0 => Dit is correct


Kan iemand dit verklaren ?

Portfolio


  • Dido
  • Registratie: Maart 2002
  • Laatst online: 15:08

Dido

heforshe

Wat is je probleem? 1.22*10^-16 is zo goed als nul.

Je hebt een afrondingsfout van wel 0,000000000000000122% gevonden ;)

Wat betekent mijn avatar?


  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Schrijf 1.22460635382238E-16 maar eens op in de normale notatie. Dat zit toch wel redelijk dicht bij nul.

En meteen het anwoord op de vraag die nu in je op komt: nee, een float heeft geen oneindige precisie, zie standaard datatype discussies, floating point uitleg en googletermen als 'strange round off error'.

{signature}


  • Gurbe de n00b
  • Registratie: Juni 2003
  • Laatst online: 08-02-2024
Oh! Ik ben zo n00b :P
Had daar even niet opgelet :P

Bedankt! :>

Portfolio


  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Iets wat ik hier steeds vaker terugzie helaas. Ik vind dit toch wel een beetje bij de basiskennis voor programmeren horen: http://en.wikipedia.org/w...g_point#Accuracy_problems

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 20:54

.oisyn

Moderator Devschuur®

Demotivational Speaker

RobIII: ik denk eerder dat de TS zich in dit geval niet realiseerde dat het antwoord dat hij kreeg weldegelijk heel dicht bij 0 lag, niet dat hij het vreemd vind dat het antwoord niet 100% exact is :)
Dido schreef op vrijdag 05 oktober 2007 @ 15:38:
Je hebt een afrondingsfout van wel 0,000000000000000122% gevonden ;)
De vraag is, is dat wel zo? Het probleem ligt 'm namelijk al bij Math.PI, dat is niet exact pi. Dit betekent dat sin(Math.PI) != sin(pi) => sin(Math.PI) != 0. Wellicht klopt het antwoord dat hij krijgt wel precies met die invoer :P

[ Voor 50% gewijzigd door .oisyn op 05-10-2007 17:03 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
.oisyn schreef op vrijdag 05 oktober 2007 @ 16:59:
RobIII: ik denk eerder dat de TS zich in dit geval niet realiseerde dat het antwoord dat hij kreeg weldegelijk heel dicht bij 0 lag, niet dat hij het vreemd vind dat het antwoord niet 100% exact is :)
Als je op de hoogte bent van die 'afrondingsfouten' dan realiseer je je denk ik toch wél snel dat 1.22460635382238E-16 zo goed als nul is (jaja, relatief dan :P ). Je weet dan namelijk dat die 'afrondingsfouten' zich meestal in die orde van grootte voordoen.

[ Voor 9% gewijzigd door RobIII op 05-10-2007 17:03 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 20:54

.oisyn

Moderator Devschuur®

Demotivational Speaker

Wellicht interpreteerde hij het juist als 1.2246 * 1016

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

.oisyn schreef op vrijdag 05 oktober 2007 @ 16:59:
De vraag is, is dat wel zo? Het probleem ligt 'm namelijk al bij Math.PI, dat is niet exact pi. Dit betekent dat sin(Math.PI) != sin(pi) => sin(Math.PI) != 0. Wellicht klopt het antwoord dat hij krijgt wel precies met die invoer :P
sin(x) ontwikkelt zich rond 0 als x, dus de nauwkeurigheid van Math.Pi en sin(Math.Pi) is van dezelfde orde van grootte, bij een ideale sin-functie. Volgens mij is de fout in het algoritme waarmee de sin benaderd wordt altijd fors kleiner dan dat, dus zit je in het gunstigste geval op 0 en in het ongunstigste geval op twee keer de onnauwkeurigheid in Pi.

Wie trösten wir uns, die Mörder aller Mörder?


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 20:54

.oisyn

Moderator Devschuur®

Demotivational Speaker

Let wel dat de x87 FPU intern werkt met 80 bits floating point getallen. Maar Math.PI is typisch een 64 bits floating point getal - de uitkomst van sin(Math.PI) heeft dus een grotere precisie dan Math.PI zelf. Natuurlijk zorgt het afdrukken in de decimale notatie ook weer voor afrondingsfouten (per vermenigvuldiging met 10 "verlies" je 2 bits precisie).

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 20:54

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ik heb even een test gedaan met windows calculator in scientific mode :) (die een 32 digit floating point representatie gebruikt). De exacte representatie van pi zoals die in een 64 bits floating point getal staat is gelijk aan
7074237752028440 * 2-51 = 3.1415926535897931159979634685442
Pi zelf, volgens windows calculator, is 3.1415926535897932384626433832795

Dat is een verschil van, jawel, 1.2246467991473550288419716939931e-16. Sin(Math.PI) volgens windows calculator is 1.2246467991473550288419944332677e-16. Dat is ongeveer gelijk, wat klopt aangezien de afgeleide van sin rond pi gelijk is aan -1. De afwijking heeft dus vooral te maken met de onnauwkeurigheid in pi zelf, ipv de daadwerkelijke implementatie van sin()

Ter vergelijking, de exacte waarde van sin(Math.PI) geretourneerd als double is 4967757600021511 * 2^-105, dat is 1.2246467991473532071737640294584e-16. Die komt 15 digits overeen met wat windows calculator als antwoord geeft, en dat is ook precies de precisie die een double heeft (53 bits binary mantissa ≈ 15.9 decimale digits). De implementatie van sin op de FPU is dus vrij exact :)

[ Voor 20% gewijzigd door .oisyn op 08-10-2007 12:18 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 17-10 16:43
.oisyn schreef op maandag 08 oktober 2007 @ 12:01:
Ik heb even een test gedaan met windows calculator in scientific mode :) (die een 32 digit floating point representatie gebruikt). De exacte representatie van pi zoals die in een 64 bits floating point getal staat is gelijk aan
7074237752028440 * 2-51 = 3.1415926535897931159979634685442
Pi zelf, volgens windows calculator, is 3.1415926535897932384626433832795

Dat is een verschil van, jawel, 1.2246467991473550288419716939931e-16. Sin(Math.PI) volgens windows calculator is 1.2246467991473550288419944332677e-16. Dat is ongeveer gelijk, wat klopt aangezien de afgeleide van sin rond pi gelijk is aan -1. De afwijking heeft dus vooral te maken met de onnauwkeurigheid in pi zelf, ipv de daadwerkelijke implementatie van sin()

Ter vergelijking, de exacte waarde van sin(Math.PI) geretourneerd als double is 4967757600021511 * 2^-105, dat is 1.2246467991473532071737640294584e-16. Die komt 15 digits overeen met wat windows calculator als antwoord geeft, en dat is ook precies de precisie die een double heeft (53 bits binary mantissa ≈ 15.9 decimale digits). De implementatie van sin op de FPU is dus vrij exact :)
toch een vrij grote afwijking, de helft van de digits zijn namelijk fout

goed:
3.141592653589793
foute rest:
1159979634685442

:o :o

~ Mijn prog blog!


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 20:54

.oisyn

Moderator Devschuur®

Demotivational Speaker

Logisch, zie de laatste alinea van mijn relaas, met name het stukje over dat een double effectief maar 15 decimale digits goed kan opslaan. Precies het aantal digits dat klopt dus ;)

(en hij doet dat natuurlijk in de vorm mantissa * 2exp, dus 7074237752028440 * 2-51. Zoiets omzetten naar het decimale stelsel wil natuurlijk niet zeggen dat je er exact 15 digits uit krijgt - het kost in het decimale stelsel meer digits om exact hetzelfde getal te representeren. Het wil slechts zeggen dat zoveel digits minimaal overeen zullen komen)

[ Voor 54% gewijzigd door .oisyn op 08-10-2007 17:35 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • PiepPiep
  • Registratie: Maart 2002
  • Laatst online: 17-11 14:00
Leuk voorbeeldje van een afrondings 'bug' in zowel ms excel als oo calc als in waarschijnlijk veel andere spreatsheet en de meeste aanverwante programma's :

Zet in cell A1 de waarde 0.2
Zet in cell A2 de formule A1*6-1
Kopieer deze formule een aantal keer naar de cellen daar weer onder en zorg dat in bv A5 de formule A4*6-1 komt. (gaat als het goed is vanzelf goed)
Bij mij in open office krijg ik als eerste in cell A20 de waarde 0,22 te zien.
Reden voor dit is dat 0.2 in binaire notatie 0.0011001100110011 enz is.

486DX2-50 16MB ECC RAM 4x 500MB Drive array 1.44MB FDD MS-Dos 6.22


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 20:54

.oisyn

Moderator Devschuur®

Demotivational Speaker

Aangezien dit Programming is, en niet Officesuites en -software:
C++:
1
2
3
4
5
6
7
8
9
int main()
{
    float f = 0.2f;
    for (int i = 0; i < 20; i++)
    {
        f = f * 6.f - 1.f;
        std::cout << f << std::endl;
    }
}

output:
0.2
0.2
0.200001
0.200004
0.200023
0.200139
0.200834
0.205006
0.230034
0.380203
1.28122
6.68732
39.1239
233.743
1401.46
8407.76
50445.6
302672
1.81603e+006
1.08962e+007


Van spreadsheet applicaties zou je echter wel verwachten dat ze een decimaal floating point formaat zouden gebruiken, omdat het typisch decimale invoer van de gebruiker verwacht.

0.2 als double is trouwens 7205759403792794 * 2-55, wat eigenlijk ~ 0.200000000000000011102230246251565404236316680908 is :)

[ Voor 26% gewijzigd door .oisyn op 09-10-2007 11:02 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

.oisyn schreef op dinsdag 09 oktober 2007 @ 10:54:
Van spreadsheet applicaties zou je echter wel verwachten dat ze een decimaal floating point formaat zouden gebruiken, omdat het typisch decimale invoer van de gebruiker verwacht.
Ik las laatst ergens (hier op T.net?) dat de core van Excel floats gebruikt vanwege performance issues jaaaaren geleden. Het is gissen waarom ze nu de core niet herschrijven, maar ik kan me voorstellen dat de Excel-code draconisch is.

Wie trösten wir uns, die Mörder aller Mörder?

Pagina: 1