[C#,PHP] Getallen afronding

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • xzaz
  • Registratie: Augustus 2005
  • Laatst online: 18-09 10:54
Goedenacht,

Ik ben bezig met een klein project, ik wil in mijn programma een uitkomst checken en deze via een website laten berekenen. De gebruiker krijgt een code die hij in een formulier kan plaatsen en daarna via de email een code krijgt meegestuurd. Deze code kan weer in het programma worden gedouwd om vervolgens te checken of hij wel of niet goed is. Nu werkt alles uitstekend op 1 ding na. De getallen verschillen:

code:
1
2
C#:  2152352095235
PHP: 2152352095240


Ik weet dat het probleem licht bij het afronden van de getallen. De uitkomst van de altijd betrouwbare rekenmachine = 2152352095235 de uitkomst van C# dus.

Dit is mijn simpele PHP code:
PHP:
1
2
3
4
function calc_serial ($id)
{
    return $key = $id * 965;
}


Weet iemand waar de oorzaak van dit probleem licht?

Schiet tussen de palen en je scoort!


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Al eens hier gekeken? Getallen en talstelsels FAQ - Afronding. Ik zie alleen geen floats er aan te pas komen en zie dus ook niet waar eventuele 'afronding' vandaan zou moeten komen? Ik ben geen PHP-er maar ik vermoed dat 't te maken heeft met een 'overflow' van een 32 bits int waardoor er gecast wordt naar een 'double' ofzo? Je getal past in elk geval niet in 32 bits, maar dan weer wel ruim in een 'double' dus dat zou de afronding ook niet écht verklaren.

Overigens: vanwaar
PHP:
1
return $key = $id * 965;
en niet gewoon
PHP:
1
return $id * 965;
:?

[ Voor 87% gewijzigd door RobIII op 21-10-2008 02:21 ]

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


Acties:
  • 0 Henk 'm!

  • xzaz
  • Registratie: Augustus 2005
  • Laatst online: 18-09 10:54
Dank je. Volgens mij heet het fenomeen "bankers rounding" in C# heb ik mijn variabelen als int64 gedefinieerd (long) maar PHP 5 ondersteund dit nog niet.
http://bugs.php.net/bug.php?id=33933 . Morgen een nieuwe dag :)

Schiet tussen de palen en je scoort!


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ik neem aan dat $id zowel in PHP als in C# gelijk is aan 2230416679? En dat het datatype in C# gelijk is aan long danwel double?

Dan kunnen er imho drie dingen aan de hand zijn.
[list=1]• Je liegt en je code is bij lange na niet zo simpel als je het hier nu stelt
• Je PHP code runt op een een of andere obscuur platform
• Je hardware bugt.
Laat ik alvast stellen dat ik punt 1 het waarschijnlijkst vind ;)

.edit: heb je niet eerder last van de representatie?
PHP:
1
2
3
$a = 2230416679 * 965;
echo $a, "<br>";
echo sprintf("%.0f", $a);

Geeft bij mij namelijk deze output:
code:
1
2
2.15235209524E+12
2152352095235

Het is duidelijk dat $a de goede waarde heeft, maar toevallig net met 1 digit te weinig wordt afgedrukt de eerste keer.

[ Voor 29% gewijzigd door .oisyn op 21-10-2008 02:42 ]

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.


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 02:21

Janoz

Moderator Devschuur®

!litemod

xzaz schreef op dinsdag 21 oktober 2008 @ 02:13:
Dank je. Volgens mij heet het fenomeen "bankers rounding" in C# heb ik mijn variabelen als int64 gedefinieerd (long) maar PHP 5 ondersteund dit nog niet.
http://bugs.php.net/bug.php?id=33933 . Morgen een nieuwe dag :)
Bankers rounding heeft hier helemaal niks mee te maken.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • PinQ
  • Registratie: Juni 2005
  • Laatst online: 09-09 13:50
Janoz schreef op dinsdag 21 oktober 2008 @ 08:59:
[...]

Bankers rounding heeft hier helemaal niks mee te maken.
Waarom niet? en wat dan wel? Ben wel benieuwd namelijk :).

"I would love to change the world, but they won't give me the source code!"


Acties:
  • 0 Henk 'm!

  • urk_forever
  • Registratie: Juni 2001
  • Laatst online: 16:10
Omdat het hele getallen zijn, en er niets afgerond wordt misschien :?

Zie ook Wikipedia over de bankers rounding. Komt erop neer dat als een getal cijfers achter de komma heeft er op een bepaalde manier afgerond wordt. Als je 2 hele getallen met elkaar vermenigvuldigt dan heb je geen cijfers achter de komma en hoef je dus niet af te ronden.

[ Voor 71% gewijzigd door urk_forever op 21-10-2008 09:26 ]

Hail to the king baby!


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

urk_forever: er wordt weldegelijk afgerond. Geen bankers' rounding idd, dat zie je zelden in floating point implementaties. Maar je hebt geen oneindige precisie. In PHP wordt een floating point getal (typisch een zogenaamde double met 53 bits mantissa) gebruikt als het niet meer in een int past (31 bits "mantissa")

Probeer zelf maar
PHP:
1
2
3
$a = 100000001;
$b = $a*$a;
echo sprintf("%.0f", $b);

Volgens mijn rekenmachine is dat toch echt 10000000200000001. PHP zegt hier 10000000200000000. Ook leuk: tel nu eens 1 bij $b op, en kijk wat de uitkomst is. Jawel, wederom 10000000200000000.

[ Voor 12% gewijzigd door .oisyn op 21-10-2008 12:47 ]

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.


Acties:
  • 0 Henk 'm!

  • xzaz
  • Registratie: Augustus 2005
  • Laatst online: 18-09 10:54
.oisyn schreef op dinsdag 21 oktober 2008 @ 02:14:
Ik neem aan dat $id zowel in PHP als in C# gelijk is aan 2230416679? En dat het datatype in C# gelijk is aan long danwel double?
30 keer gecheckt/gedebugt zijn allemaal het zelfde.
Dan kunnen er imho drie dingen aan de hand zijn.
[list=1]• Je liegt en je code is bij lange na niet zo simpel als je het hier nu stelt
Mijn code is zo simpel als het hier boven staat het wordt in een header geparst om het later te versturen naar de geadresseerde.
Dit is mijn C# code:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
        private Int64 id;
        private Int64 serial;
        private Int64 intcode;

           // HD id
            VolumeID GetID = new VolumeID();
            // Set de tekst in de txt
            txtHDID.Text = GetID.GetVolumeSerial("C");

            // pak als id
            id = Convert.ToInt64(GetID.GetVolumeSerial("C"));

            // vermenigvul code
            intcode = 965;

            // Bereken serial
            serial = id * intcode; //* System.DateTime.Now.Year;

En het enige wat ik heb, variabelen worden goed gevuld.
[quote]
• Je PHP code runt op een een of andere obscuur platform
• Je hardware bugt.
Laat ik alvast stellen dat ik punt 1 het waarschijnlijkst vind ;)
.edit: heb je niet eerder last van de representatie?
PHP:
1
2
3
$a = 2230416679 * 965;
echo $a, "<br>";
echo sprintf("%.0f", $a);

Geeft bij mij namelijk deze output:
code:
1
2
2.15235209524E+12
2152352095235

Het is duidelijk dat $a de goede waarde heeft, maar toevallig net met 1 digit te weinig wordt afgedrukt de eerste keer.
En op welke manier kan ik er nu voor zorgen dat de uitkomsten altijd gelijk zijn?

Schiet tussen de palen en je scoort!


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
xzaz schreef op dinsdag 21 oktober 2008 @ 12:27:
Dat is mijn C# code (bestaan er ook C# tags?). En het enige
Overzicht van UBB-codes #tag_code ;)

En nu we je C# code zien (die de toch al de juiste uitkomst gaf...), waar is je (hele, maar enkel relevante!) PHP code? Is dat enkel het stuk uit TS? Waar is de aanroep van calc_serial en hoe komt de waarde in de aanroep tot stand?

[ Voor 34% gewijzigd door RobIII op 21-10-2008 12:31 ]

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


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

Euh ja, we hebben natuurlijk niets aan de C# code, die was al correct. Het ging om de PHP code, die incorrect was volgens jou :)

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.


Acties:
  • 0 Henk 'm!

  • xzaz
  • Registratie: Augustus 2005
  • Laatst online: 18-09 10:54
Er is verder na het aanroeren wao de functie geen relevante code. Ik zit nu in de trein post straks dat hele mail script wel.

Schiet tussen de palen en je scoort!


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Euh, doe me een lol en beperk je tot de voor dit probleem relevante code... Ik zou graag zien hoe je calc_serial aanroept en hoe de waarde waarmee je 'm aanroept tot stand komt. Hoe je mailt boeit niet.

[ Voor 24% gewijzigd door RobIII op 21-10-2008 12:47 ]

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


Acties:
  • 0 Henk 'm!

  • xzaz
  • Registratie: Augustus 2005
  • Laatst online: 18-09 10:54
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
function licentie_proc($computernaam,$hdid)
{
    if(empty($_POST)){
        echo '<p class="rood_melding">Sorry er iets fout gegegaan, weet u zeker dat u een computernaam en een goede code heeft opgegeven?</p>';
        
    }else{
    $serial = calc_serial($hdid);

                //De rest van de mail script dit hieronder zit als content van de email
                 <tr>
         <td>Licentie code</td><td>'. $serial . '</td>
    </tr>
             }


En hier vraagt hij licentie_proc aan met de gevulde waardes:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
switch($_GET['actie']){
        // Pagina's
        case "verlengen": 
        echo $uitleg['licentie_verlengen'];
        echo licentie_verlengen($_GET['id']); break;
        case "nieuw":
        echo $uitleg['licentie_nieuw'];
        licentie_nieuw(); break;
        case "nieuw_proc":
        licentie_proc($_POST['computernaam'],$_POST['computerid']); break;
        }
?>

[ Voor 0% gewijzigd door een moderator op 21-10-2008 13:50 . Reden: Code tags gefixed... ]

Schiet tussen de palen en je scoort!


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

Maak van die $serial dan eens sprintf("%.0f", $serial) op regel 11.

[ Voor 4% gewijzigd door .oisyn op 21-10-2008 13:51 ]

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.


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
xzaz schreef op dinsdag 21 oktober 2008 @ 13:47:
PHP:
1
<p class="rood_melding">
offtopic:
Het is onverstandig om een class te noemen naar hoe 'ie er uit ziet; wat als je 'm straks blauw maakt in de CSS? Kies liever een naam als "error_melding" ofzo.


Dus $hdid komt uit $_POST['computerid']... ik zie het probleem niet zo gauw dan behalve dat het een string of ander verkeerd type zou kunnen zijn, maar again: ik ben geen PHP-er en volgens mij boeit het in PHP niet.
Ik mis overigens wel de nodige checks e.d.
.oisyn schreef op dinsdag 21 oktober 2008 @ 13:51:
Maak van die $serial dan eens sprintf("%.0f", $serial) op regel 11.
Ah, of inderdaad natuurlijk de output finetunen :Y)

[ Voor 23% gewijzigd door RobIII op 21-10-2008 13:54 ]

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


Acties:
  • 0 Henk 'm!

Verwijderd

PHP maakt hier gewoon een float van inderdaad, iets waar je binnen 3 sec achter had kunnen komen door simpelweg even een var_dump te proberen. ;)

Floats hebben geen exacte waarde zoals ook in de reeds genoemde FAQ staat beschreven, vandaar het verschil.

Even uit de manual:

http://nl.php.net/manual/en/language.types.integer.php
Integer overflow

If PHP encounters a number beyond the bounds of the integer type, it will be interpreted as a float instead. Also, an operation which results in a number beyond the bounds of the integer type will return a float instead.
Op diezelfde pagina staat dus dat default in PHP een int 32 bit signed is.

[ Voor 45% gewijzigd door Verwijderd op 21-10-2008 14:01 ]


Acties:
  • 0 Henk 'm!

  • tech-no-logical
  • Registratie: December 2000
  • Laatst online: 17-09 22:52
indien alles faalt : http://nl.php.net/manual/en/function.bcmul.php
die geeft gewoon strings terug, en is sinds php4.0.4 standaard aanwezig.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op dinsdag 21 oktober 2008 @ 13:56:
Floats hebben geen exacte waarde zoals ook in de reeds genoemde FAQ staat beschreven, vandaar het verschil.
Zoals ik al zei, dit getal past gewoon in een float. En bovendien is het natuurlijk niet zo dat floats per definitie geen exacte waarde hebben. Elke waarde die een float aan kan nemen is exact. Het probleem is meer dat (net als bij int) niet alle mogelijke waarden door een float gerepresenteerd kunnen worden. Daar valt dit getal echter niet onder.

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.


Acties:
  • 0 Henk 'm!

Verwijderd

.oisyn schreef op dinsdag 21 oktober 2008 @ 14:21:
[...]

Zoals ik al zei, dit getal past gewoon in een float. En bovendien is het natuurlijk niet zo dat floats per definitie geen exacte waarde hebben. Elke waarde die een float aan kan nemen is exact. Het probleem is meer dat (net als bij int) niet alle mogelijke waarden door een float gerepresenteerd kunnen worden. Daar valt dit getal echter niet onder.
Je hebt helemaal gelijk, het probleem lijkt inderdaad puur te zitten in de weergave van PHP. De waarde in het geheugen lijkt wel gewoon 100% te kloppen. De sprintf functie doet het wel goed dus waarom PHP het zelf fout doet is mij een raadsel.

Bij vergelijken doet ie het ook goed var_dump(2152352095235 == 2152352095240) geeft wel false.

[ Voor 6% gewijzigd door Verwijderd op 21-10-2008 15:15 ]


Acties:
  • 0 Henk 'm!

  • xzaz
  • Registratie: Augustus 2005
  • Laatst online: 18-09 10:54
De sprintf did the trick. En php geeft nu de juiste waarde. Bedankt voor het meedenken.

rood_melding ook even aangepast. Bedankt

Schiet tussen de palen en je scoort!


Acties:
  • 0 Henk 'm!

Verwijderd

De truc is dat PHP altijd al de juiste waarde had ;)

sprintf is puur weergave, niets meer en niets minder.

Ik vind het wel een interessante bug eigenlijk...

Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
In php.ini staat een setting "precision"; doet die nog wat hiermee?
code:
1
2
; The number of significant digits displayed in floating point numbers.
precision    =  12

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


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

Dat verklaart wel waarom de 13e digit nou juist niet weergegeven werd :)

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.


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
.oisyn schreef op dinsdag 21 oktober 2008 @ 17:59:
Dat verklaart wel waarom de 13e digit nou juist niet weergegeven werd :)
:D Ik kwam het zojuist geheel toevallig tegen in een php.ini en m'n oog viel er nét op.

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

Pagina: 1