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

[PHP] 32 bit integer (hex)

Pagina: 1
Acties:

  • Satom
  • Registratie: Mei 2011
  • Laatst online: 26-10 22:27

Satom

Verzamel ervaringen

Topicstarter
Beste Tweakers,

Op het moment zit ik met een kleine probleem. Ik heb in C# een werkend programma, voor de PRNG waarmee ik wil gaan werken.

De bedoeling was om het te gebruiken om een Windows-based server, maar vanwege financiële redenen word er nu gebruikt gemaakt van een Linux-based NAS (server). Dus vandaar dat ik eerst het programma in C# heb geschreven en nu graag in PHP wil hebben.

De waarde waarmee ik moet werken / die ik verwacht, is een 32-bit hexadecimale getal.

Hieronder de code, dat ik geschreven heb in C# (trouwens niet volledige code)

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
            private UInt32 m_seed;

            public UInt32 Next()
            {
                return (0x41c64e6d * m_seed) + 0x6073;
            }

            public UInt32 NextNum()
            {
                m_seed = Next();
                return m_seed;
            }

m_seed = 0xFF82

NextNum();


Door de functie NextNum() aan te roepen word de variabel m_seed gevuld met een 32 bits integer (word weliswaar ge-returned als een decimaal getal, maar zet het zelf om in hexadecimaal, van 0x00000000 tot 0xFFFFFFFF). Door de UInt32 word de waarde terug gebracht / getrimt naar 32 bits, het is dus een D-Word. Alleen doet PHP dat niet en geeft gewoon een Q-Word terug (64 bits?), waardoor er niets meer klopt.

Ik ben zelf ten einde raad, want zou niet weten hoe ik hierop moet zoeken en hoe ik het zelf zou moeten oplossen.. :$

Zat te denken aan substr($string, -8); maar lijkt mij niet echt de juiste manier..

Alvast bedankt!

  • Paul
  • Registratie: September 2000
  • Nu online
Satom schreef op woensdag 31 oktober 2012 @ 09:17:
Door de functie NextNum() aan te roepen word de variabel m_seed gevuld met een getal (word weliswaar ge-returned als een getal, maar zet het zelf om in een getal, van 0 tot max(uint32_t). Door het datatype waarin ik dat getal opsla word de waarde terug gebracht / getrimt naar [b]maximaal ~4,2*109, het is dus een D-Word. Alleen doet PHP dat niet en geeft gewoon een Q-Word terug (64 bits?), waardoor er niets meer klopt.
Wat wil je bereiken? Ik denk dat je namelijk 2 dingen heel erg door elkaar haalt: de waarde (in welke notatie of getallenstelsel dan ook, die zijn namelijk uitwisselbaar [even zaken als significantie daargelaten]) die je hebt, en de representatie ervan :)

Je kunt heel goed je code herschrijven naar een andere notatie en dan doet het nog gewoon hetzelfde...
PHP:
1
return (1103515245 * m_seed) + 24691;

Waar je bij 32bit integers wel op moet letten is dat je niet krijgt wat je verwacht wanneer m_seed hoger is dan ~3,8, dan overflowt je 32bit integer.

Dat lijkt by design te zijn, en dan moet je misschien de hele boel modulo max(uint32) doen. Dan heb je alsnog een 'getal', geen 'hexidecimaal getal', dat is gewoon representatie :)

"Your life is yours alone. Rise up and live it." - Richard Rahl
Rhàshan - Aditu Sunlock


  • Satom
  • Registratie: Mei 2011
  • Laatst online: 26-10 22:27

Satom

Verzamel ervaringen

Topicstarter
Bedankt voor je snelle reactie :) ,

Dit is nu het exacte probleem:

Als m_seed = 0xFF82 (dus 62088),

word de som: (1103515245 * 62088) + 24691, het antwoord hiervan is: 68515054556251 (dec), 0x3E50677D145B (hex), alleen verwachtte ik het volgende:

1736250459 (dec), 677D145B (hex).

Maar na het beter lezen van jouw post, kom ik tot de volgende conclusie; Wat hopelijk gaat werken.

PHP:
1
2
if (m_seed > 0xFFFFFFFF) { m_seed = m_seed % 0xFFFFFFFF; }
else { /* we hoeven niets doen*/ }


Ik zal het gelijk even in de praktijk proberen :)

  • Hydra
  • Registratie: September 2000
  • Laatst online: 06-10 13:59
Even iets anders: je kunt gewoon op Linux via Mono .Net applicaties draaien he?

https://niels.nu


  • Paul
  • Registratie: September 2000
  • Nu online
Yup, de overflow van je 32bit int gebruik je by design, dus als je dan een grotere hebt moet je de rest na deling (modulo) hebben.

Waarom PHP je een 64bit integer geeft als je een 32bit int declareert is me een raadselAls ik de handleiding van PHP m.b.t. integers erbij pak blijkt dat PHP het concept '32bit int' en '64 bit int' helemaal niet kent, een int is een int is een int, en is afhankelijk van je platform.

Je zou dus ook een 32bit OS (of slechts PHP-versie) kunnen draaien :P

"Your life is yours alone. Rise up and live it." - Richard Rahl
Rhàshan - Aditu Sunlock


  • Hydra
  • Registratie: September 2000
  • Laatst online: 06-10 13:59
PHP is in de basis ook een dunne schil om de C library en daarvoor geldt hetzelfde.

https://niels.nu


  • Satom
  • Registratie: Mei 2011
  • Laatst online: 26-10 22:27

Satom

Verzamel ervaringen

Topicstarter
Hydra schreef op woensdag 31 oktober 2012 @ 09:46:
Even iets anders: je kunt gewoon op Linux via Mono .Net applicaties draaien he?
Ook via PuTTy? Aangezien dat de enige mogelijkheid is om contact te maken met de NAS én het moet ook nog eens aanspreekbaar zijn via het web, python of cron(job)(tab).
Paul schreef op woensdag 31 oktober 2012 @ 09:52:
Yup, de overflow van je 32bit int gebruik je by design, dus als je dan een grotere hebt moet je de rest na deling (modulo) hebben.

[s]Waarom PHP je een 64bit integer geeft als je een 32bit int declareert is me een raadsel[s/]Als ik de handleiding van PHP m.b.t. integers erbij pak blijkt dat PHP het concept '32bit int' en '64 bit int' helemaal niet kent, een int is een int is een int, en is afhankelijk van je platform.

Je zou dus ook een 32bit OS (of slechts PHP-versie) kunnen draaien :P
Hm, ik heb een 32bit Windows 8 + 32bit Wampserver (geen ftp op NAS) + 32bit PHP.. word me steeds gekker.. :?

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:38

.oisyn

Moderator Devschuur®

Demotivational Speaker

Satom schreef op woensdag 31 oktober 2012 @ 09:38:
Maar na het beter lezen van jouw post, kom ik tot de volgende conclusie; Wat hopelijk gaat werken.

PHP:
1
2
if (m_seed > 0xFFFFFFFF) { m_seed = m_seed % 0xFFFFFFFF; }
else { /* we hoeven niets doen*/ }
Nee, dat doet niet wat je wilt. Je wilt namelijk modulo 232, oftewel in hex 0x100000000. De IF is ook een beetje onzinnig, je kunt de modulo net zo goed altijd doen. Het alternatief is dat je een bitwise AND doet met 0xffffffff. Ook kun je gewoon casten naar int.

Wat er onder water overigens gebeurt is dat er een double van wordt gemaakt die wel genoeg precisie heeft om het hele getal na de vermenigvuldiging te representeren. Vandaar dat de cast naar int ook gewoon werkt.

.edit: nee wacht, het gaat uiteindelijk fout want je past de seed steeds aan. Een double heeft maar 53 significante bits. Hoewel de eerste vermenigvuldiging maar maximaal 48 bits zal beslaan aangezien m_seed in eerste instantie in 16 bits past, zal de volgende iteratie wel buiten het bereik van een double komen te liggen.

[ Voor 23% gewijzigd door .oisyn op 31-10-2012 10:09 ]

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.


  • Satom
  • Registratie: Mei 2011
  • Laatst online: 26-10 22:27

Satom

Verzamel ervaringen

Topicstarter
Hm, in PHP werkt het inderdaad niet, maar met de rekenmachine van Windows krijg ik precies wat ik wil als ik 68515054556251 % 0xFFFFFFFF intoetste :P

Maar als ik jou goed begrepen heb, moest ik één van de onderstaande proberen;

PHP:
1
2
3
4
.
echo (((1103515245 * 62088) + 24691) % 0xFFFFFFFF); //0
echo (((1103515245 * 62088) + 24691) % 0x100000000); //0
echo (((1103515245 * 62088) + 24691) ); //68515054556251


Wat je precies bedoelt met Ook kun je gewoon casten naar int snap ik niet helemaal :$

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:38

.oisyn

Moderator Devschuur®

Demotivational Speaker

maar met de rekenmachine van Windows krijg ik precies wat ik wil als ik 68515054556251 % 0xFFFFFFFF
Euh nee, dan zit je er écht een paar naast.
0x3e50677d145b % 0xffffffff = 0x677d52ab
Die cijfers komen helemaal niet overeen met het origineel. Hier wel:
0x3e50677d145b % 0x100000000 = 0x677d145b
Wat je precies bedoelt met Ook kun je gewoon casten naar int snap ik niet helemaal
Ik bedoel
PHP:
1
return (int)((0x41c64e6d * m_seed) + 0x6073);

Maar een AND is handiger want een int is niet gegarandeerd 32 bits in PHP.

Maar zoals ik net in mijn edit zei, dit gaat 1 keer goed, daarna niet meer. Want dan is m_seed gelijk aan 0xeed2c6cd, en 0x41c64e6d * 0xeed2c6cd past niet in een double.

Maar daar kun je eventueel wel omheen met een trucje:
PHP:
1
2
3
$p1 = 0x41c6 * m_seed;
$p2 = 0x4e6d * m_seed;
return (($p1 << 16) + $p2 + 0x6073) & 0xffffffff;


Wat in feite gewoon vermenigvuldigen is zoals je dat op de basisschool hebt geleerd ;)

[ Voor 10% gewijzigd door .oisyn op 31-10-2012 10:21 ]

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.


  • Paul
  • Registratie: September 2000
  • Nu online
Hydra schreef op woensdag 31 oktober 2012 @ 09:53:
PHP is in de basis ook een dunne schil om de C library en daarvoor geldt hetzelfde.
Ik kan in C een uint8_t declareren, en als ik daar 256 in gooi krijg ik een 0 terug (of heeeel misschien een foutmelding). In PHP krijg je dan, als ik de manual goed lees, gewoon 256 terug, en daar zit het probleem zo te zien :)

Ik ben absoluut geen PHP-guru, sterker nog, ik heb er enkel bij bestaande producten her en der 1 of 2 regeltjes in aangepast, maar waarom zou PHP van een vermenigvuldiging met 2 integers een double maken? De manual rept helaas alleen bij delen over het type, maar zelfs daar geven ze bij een deling tussen integers die een geheel getal oplevert een integer terug.

"Your life is yours alone. Rise up and live it." - Richard Rahl
Rhàshan - Aditu Sunlock


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:38

.oisyn

Moderator Devschuur®

Demotivational Speaker

Operands of modulus are converted to integers (by stripping the decimal part) before processing.
Ah, dat verklaart iig waarom dat niet werkte :)
Maar ook: zucht, waarom zou je niet gewoon modulus met doubles laten werken |:(
maar zelfs daar geven ze bij een deling tussen integers die een geheel getal oplevert een integer terug.
Alleen als het een geheel getal oplevert dus, niet als het dat niet doet. Dus waarom je dit als reden ziet dat ze bij vermenigvuldigen dan wel een int teruggeven als het niet past snap ik niet helemaal. Wellicht omdat je denkt dat het criterium is dat het een geheel getal moet zjin, in plaats van dat het representeerbaar moet zijn door een int?

Maar verder: http://www.php.net/manual/en/language.types.integer.php
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.

[ Voor 30% gewijzigd door .oisyn op 31-10-2012 10:40 ]

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.


  • Satom
  • Registratie: Mei 2011
  • Laatst online: 26-10 22:27

Satom

Verzamel ervaringen

Topicstarter
Oké! Ben nog even wat aan proberen geweest;

Complete code:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php

/**
 * @author Kevin
 * @copyright 2012
 * @category Decrypt file
 */

$_seed = 0;

function Update()
{
    global $_seed;
    $_seed = (($_seed * 0x41C64E6D + 0x6073) & 0xFFFFFFFF);
}

function getRand()
{
    global $_seed;
    Update();
    return ($_seed);

}

for ($i = 0; $i <= 10; $i += 1) {

    echo dechex(getRand()) . "<br>";
}

?>


En een plaatje, de rechter scherm is de waardes die ik graag in het linker scherm wil zien. En we komen nu ergens,

Afbeeldingslocatie: http://i.imgur.com/tBVRB.png

De eerste twee waardes komen geheel overeen, bij de derde komen de eerste 6 cijfers/karakters overeen en vanaf daar gaat het mis =/

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:38

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ik heb je al uitgelegd waarom dat is en een oplossing aangedragen :)

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.


  • Hydra
  • Registratie: September 2000
  • Laatst online: 06-10 13:59
Paul schreef op woensdag 31 oktober 2012 @ 10:26:
[...]
Ik kan in C een uint8_t declareren, en als ik daar 256 in gooi krijg ik een 0 terug (of heeeel misschien een foutmelding). In PHP krijg je dan, als ik de manual goed lees, gewoon 256 terug, en daar zit het probleem zo te zien :)
Je had het over een basistype int, daarvoor geldt over het algemeen in C (en dialecten) dat daarvoor het platform gevolgd wordt. Specifieke groottes als uint8 zijn een ander verhaal maar dat soort zaken hebben IMHO geen plaats in een scripttaal als PHP.

https://niels.nu


  • Paul
  • Registratie: September 2000
  • Nu online
.oisyn schreef op woensdag 31 oktober 2012 @ 10:38:
Alleen als het een geheel getal oplevert dus, niet als het dat niet doet.
Dat zeg ik :P
Dus waarom je dit als reden ziet dat ze bij vermenigvuldigen dan wel een int teruggeven
omdat ze out of their way gaan om maar een int terug te geven, in andere talen moet je dan casten of een andere operator gebruiken, bij PHP gaan ze het zelf evalueren en beslissen wat er terug moet komen. Ergo, waarom zou je bij een vermenigvuldiging van integers, iets dat per definitie een geheel getal oplevert, opeens een floating point type terug gaan geven als je bij iets waarvan je er vanuit kunt gaan dat het meer kommagetallen dan gehele getallen oplevert wel gaat kijken of het niet toevallig een geheel getal oplevert?
als het niet past
Kijk, en dat stukje miste ik dus :) Maar in deze is PHP dus weer de vreemde eend, alle andere talen (die ik ken :P ) overflowen en beginnen opnieuw.
Hydra schreef op woensdag 31 oktober 2012 @ 11:01:
Je had het over een basistype int
Dat is dan (begrijpelijk :) ) iets te letterlijk geïnterpreteerd, ik had het namelijk over
Specifieke groottes
zoals de expliciet gedefinieerde UInt32 die de TS all over the place gebruikt :) _iedere_ int (8, 16, 32, 64, 12½, pi) is zo te lezen even groot en platformafhankelijk?

[ Voor 3% gewijzigd door Paul op 31-10-2012 11:13 ]

"Your life is yours alone. Rise up and live it." - Richard Rahl
Rhàshan - Aditu Sunlock


  • Satom
  • Registratie: Mei 2011
  • Laatst online: 26-10 22:27

Satom

Verzamel ervaringen

Topicstarter
.oisyn schreef op woensdag 31 oktober 2012 @ 10:56:
Ik heb je al uitgelegd waarom dat is en een oplossing aangedragen :)
Inderdaad! Het werkt nu perfect :+ Alleen wat ik mij nog afvraag (hoop dat je het niet erg vind), $p1 ga je right shiften, maar $p2 niet,

En voor de liefhebbers, de werkende code :)
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php

/**
 * @author Kevin & Tweakers :)
 * @copyright 2012
 * @category Decrypt file
 */

$_seed = 0;

function Update()
{
    global $_seed;

    $p1 = 0x41c6 * $_seed;
    $p2 = 0x4e6d * $_seed;

    $_seed = ((($p1 << 16) + $p2 + 0x6073) & 0xffffffff);
}

function getRand()
{
    global $_seed;
    Update();

    return ($_seed);

}

for ($i = 0; $i <= 1000; $i += 1) {

    echo dechex(getRand()) . "<br>";
}

?>

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:38

.oisyn

Moderator Devschuur®

Demotivational Speaker

Paul schreef op woensdag 31 oktober 2012 @ 11:12:
omdat ze out of their way gaan om maar een int terug te geven, in andere talen moet je dan casten of een andere operator gebruiken, bij PHP gaan ze het zelf evalueren en beslissen wat er terug moet komen.
Dat is vrij standaard met loosely typed talen. In JavaScript bijvoorbeeld is er niet eens een distinctie tussen ints en floats, getallen zijn dan gewoon een number. Python schakelt doodleuk over op arbitrary precision arithmetic als iets niet past. Ruby doet bij mijn weten niet veel anders.
Kijk, en dat stukje miste ik dus :) Maar in deze is PHP dus weer de vreemde eend, alle andere talen (die ik ken :P ) overflowen en beginnen opnieuw.
Je kent dus gewoon niet veel talen ;)

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: 01:38

.oisyn

Moderator Devschuur®

Demotivational Speaker

Satom schreef op woensdag 31 oktober 2012 @ 11:19:
[...]
Inderdaad! Het werkt nu perfect :+ Alleen wat ik mij nog afvraag (hoop dat je het niet erg vind), $p1 ga je right shiften, maar $p2 niet,
Zoals ik al zei, basisschool vermenigvuldigen :)

Vroegâh, als je bijvoorbeeld 23×7 wilde uitrekenen, dan deed je:

  7
 23 ×
-----
 21
140 +
-----
161


Oftewel, je deed 3×7 + 2×7×10

Welnu, gebruik makend van het feit dat PHP een double teruggeeft als het niet in een int past, en het feit dat er in een double ruimte is voor 53 bits aan precisie, deel ik de vermenigvuldiging van 2 32-bits getallen op in 2 vermenigvuldigingen van een 32-bits getal met een 16-bits getal (wat een resultaat van maximaal 48 bits geeft), door 1 van de 32-bits getallen (die constante) in tweeën te hakken. Net zoals je de 23 in het voorbeeld hierboven ophakt in een 2 en in een 3. Omdat de hoogste 16 bits meer significantie hebben shift je die waarde met 16, net zoals je de 2 nog met 10 vermenigvuldigt.

[ Voor 178% gewijzigd door .oisyn op 31-10-2012 11:32 ]

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.


  • Paul
  • Registratie: September 2000
  • Nu online
.oisyn schreef op woensdag 31 oktober 2012 @ 11:20:
Je kent dus gewoon niet veel talen ;)
Tja, ben er al een paar jaar uit :P Ik denk dat het met C#, C++, C, Java, Delphi, Pascal en Basic (oh, en een beetje Perl) een heel eind ophoudt, maar dan heb (of had?) je wel meteen (imho) het grootste deel van de markt te pakken.

Niet dat ik andere talen wil marginaliseren maar als je niks met webdevelopment doet kom je niet zo snel in aanraking met Javascript, PHP etc :P

"Your life is yours alone. Rise up and live it." - Richard Rahl
Rhàshan - Aditu Sunlock


  • Satom
  • Registratie: Mei 2011
  • Laatst online: 26-10 22:27

Satom

Verzamel ervaringen

Topicstarter
.oisyn schreef op woensdag 31 oktober 2012 @ 11:24:
[...]

Zoals ik al zei, basisschool vermenigvuldigen :)

Vroegâh, als je bijvoorbeeld 23×7 wilde uitrekenen, dan deed je:

  7
 23 ×
-----
 21
140 +
-----
161


Oftewel, je deed 3×7 + 2×7×10

Welnu, gebruik makend van het feit dat PHP een double teruggeeft als het niet in een int past, en het feit dat er in een double ruimte is voor 53 bits aan precisie, deel ik de vermenigvuldiging van 2 32-bits getallen op in 2 vermenigvuldigingen van een 32-bits getal met een 16-bits getal (wat een resultaat van maximaal 48 bits geeft), door 1 van de 32-bits getallen (die constante) in tweeën te hakken. Net zoals je de 23 in het voorbeeld hierboven ophakt in een 2 en in een 3. Omdat de hoogste 16 bits meer significantie hebben shift je die waarde met 16, net zoals je de 2 nog met 10 vermenigvuldigt.
Mijn dank is mega groot! Ik snap nu precies waarom het zo moet en niet anders! Ben nu al een aardig eindje op weg _/-\o_
Pagina: 1