[PHP] Integer overflow met willekeurige upper/lower bounds

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

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
ik zit met het volgende waar ik niet helemaal uitkom.

ik heb een classe welke een integer voor moet stellen. de lower en upper bound zijn volledige zelf in te stellen en nu probeer ik het zo te maken dat elke integer waarde die je er aan geeft mapt of overflowed naar een getal binnen de range die gezet is door de waardes van de upper en lower bound.

dus stel dat ik de lower bound instel op 5 en de upper op 15 en ik probeer een waarde 17 eraan te geven dat wordt de werkelijke waarde gesteld op 6. ik ben nu zover dat ik dit werkend heb maar alleen indien de lower-bound <= 0 en de upper > 0. hier is de mijn huidige code:
PHP:
1
2
3
4
5
 $lower = -5;
 $upper = 15;
 $input = 135;

 $value = (($value - $lower) % (($upper - $lower) + 1)) + $lower);


helaas krijg ik het niet werkend zodra lower > 0. ik denk dat dit komt omdat ik de waarde eerst compenseer naar 0 en dan pas de modulus er op los laat omdat later weer te compenseeren voor het werkelijke getal. volgensmij denk ik veel te moeilijk maar het enige alternatief dat ik zie is een complexe while loop wat niet echt goed is voor de performance volgensmij.

wie o wie helpt mij?

Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 19:15
Wat werkt er nu niet dan, behalve dat haakje teveel op regel vijf en dat je input schrijft op regel 3 en value op regel 5? (Beetje slordig om hier een vraag te stellen en dan in vier regels PHP code twee simpele fouten te maken.)

De methode is goed (als we even buiten beschouwing laten dat de integers van PHP ook kunnen overflowen, maar zolang je onder pak-'m-beet een miljard blijft is dat geen probleem). En als je $lower = 5, $upper = 15, $input = 17 doet, komt er ook gewoon 6 uit. Dus, wat wil je nu?

(Het gaat overigens nog wel fout als je invoer kleiner is dan $lower. Ik weet niet of PHP ueberhaupt garanties geeft over de werking van de modulus operator in dat geval.)

offtopic:
En gebruik alsjeblieft hoofdletters.

[ Voor 24% gewijzigd door Soultaker op 20-10-2007 01:29 ]


Acties:
  • 0 Henk 'm!

  • P.O. Box
  • Registratie: Augustus 2005
  • Niet online
wat me niet duidelijk is.... wat wil je dat de waarde wordt als de lowerbound = -5 en de upperbound = 15, en de input een waarde heeft van 6...
moet dan de waarde worden 6.... of moet de waarde worden 1 ??
in het laatste geval is het makkelijk, in het eerste geval moet je, voor zover ik het nu zie om drie uur 's nachts ;), er ook een if-constructie in bouwen...

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Sorry, was inderdaad 2 haakjes vergeten.

Wat ik wil doen is het zelfde gedrag creeeren zoals bijvoorbeeld een 8bit integer overflowed. Dus van 126, 127, -128, -127 etc. Maar dan dus met een willekeurige upper&lower bound. En een waarde die dus lager of hoger dan de upper of lower bound is moet dus worden omgezet naar een waarde die binnen dat bereik ligt en mogelijk zelfs meerdere keeren overflowed.

Als de lowerbound -5 is en de upperbound 15 dan is een waarde van 1 dus eigenlijk 7 omdat het begin van het bereik verplaatst is naar -5 en niet 0. Je begint dus zegmaar met tellen vanaf -5 en bij 15 overflow je weer terug naar -5.

Ik heb het immidels opgelost. Mischien niet de schoonste oplossing maar wel de minst bug gevoelige. Waarschijnlijk heeft de modulus operator iets met negative opperands. Hier is mijn oplossing voor een ieder die er mischien wat aan heeft. Dit zou zelfs kunnen werken met floats terwijl de modulus operator altijd de operands omzet naar integers.


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
 function overflow($input, $upper, $lower)
 {
  if(!is_int($input)){
   return false;
  }
  if(!is_int($upper)){
   return false;
  }
  if(!is_int($lower)){
   return false;
  }
  if($upper <= $lower){
   return false;
  }

  $range = $upper - $lower;
  $ouput = $input;

    while($output >= $upper){
     $output = $output - $range;
    }
    while($output < $lower){
     $output = $output + $range;
    }
  
  return $output;
 }

Acties:
  • 0 Henk 'm!

  • Bolukan
  • Registratie: Oktober 2002
  • Laatst online: 23-08 23:43
Ik zou dat nog even corrigeren tot:
PHP:
1
  $range = $upper - $lower + 1;

Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 19:15
@Bolukan: waarschijnlijk is het bereik van $lower (inclusief) tot $upper (exclusief), waardoor de code van Docey wel zinnig is. Dat leidt ik af uit zijn condities op regel 12 en 19.

Verder: in de TS schrijf je dat je die while-lusjes juist wil vermijden. Dat kan ook, lijkt me:
PHP:
1
2
3
4
5
if ($input >= $lower)
  $output = $input + ($input - $lower)%$range;
else
if ($input < $lower)
  $output = $upper - 1 + (($lower - $input - 1)%$range);

(Die tweede expressie moet je misschien nog even dubbelchecken/testen. ;))

Acties:
  • 0 Henk 'm!

  • Bolukan
  • Registratie: Oktober 2002
  • Laatst online: 23-08 23:43
Verwijderd schreef op zaterdag 20 oktober 2007 @ 01:15:
dus stel dat ik de lower bound instel op 5 en de upper op 15 en ik probeer een waarde 17 eraan te geven dat wordt de werkelijke waarde gesteld op 6.
@Soultaker: 16 wordt 5 en 17 wordt 6, lijkt me dan niet: 15 doet gewoon mee. Maakt mij even niet uit, wie gelijk heeft: als Docey er maar even over nadenkt.

NB: Zie ook zijn code: (($upper - $lower) + 1))

Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 19:15
Dat lijkt me de oudere code die inderdaad een andere conventie aanhoudt. Maar de nieuwe code is ook consistent; kijk bijvoorbeeld op regels 19-21: als je er $input == $upper ingooit, wordt dat gemapt naar $lower.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Dit was inderdaad een denk fout van mijn kant wat ook enigsinds het vreemde gedrag van de modulus operator verklaarde. Het is lower inclusief en upper exclusief. Precies zoals een 8bit signed integer loopt van -128 tot 128 maar de upper niet mee telt en overflowed op 127.

Ik heb zelf eens flink lopen spelen met de modulus operator en vooral met negative operands is deze nogal eens onverspelbaar. Ik daarom besloten de modulus operator voor negative getallen maar beter te vermijden nog afgezien van het feit dat deze geen floats doet.

Voor de gene die zich afvragen waarom ik dit allemaal doe? PHP5 heeft een leuke nieuwe feature namelijk 'type hinting'. Deze werkt alleen met objects(en arrays) en kan PHP5 iets meer strong-typed maken en heel wat lijnen van argument checking overbodig maken.

Ik ben dus bezig de 'primitieve' data-typen in een object te stopen. Of het sneller is zal nog moeten blijken maar ik kan in iedergeval de is_int()'s en de is_float()'s of is_string()'s in een plek schrijven en in combinatie met exceptions zou dat heel wat if's kunnen schelen.
Pagina: 1