Jump to content
php.lv forumi

aizsardzibas sistemas majaslapam, papildus drosibai


Devils666

Recommended Posts

bubu, tu mani gandrīz nobaidīji :P

bet...

$i = 1152921504606846976;  // pow(2, 60)
$n = (float) $i;

echo gettype($i) . ' ' . gettype($n) . '<br />';  // integer double
echo $n == 1152921504606846976 ? 'true' : 'false';  // true

tests tika izpildīts uz nano.lv servera, kuram jau pēc phpinfo() pirmās rindiņas var spriest, ka tam ir 64bit cpu

System: Linux if24.nano.lv 2.6.26.3-grsec #1 SMP Fri Sep 12 21:25:22 EEST 2008 x86_64

Link to comment
Share on other sites

  • Replies 31
  • Created
  • Last Reply

Top Posters In This Topic

Pamēģini tagad skaitli 1152921504606846975. Paskaties, ko tad tev teiks.

Ņem vērā, ka floati/doubļi skaitli glabā formā mantisa*2^eksponente. Ja mantisa ir 1 un eksponente 60, tad loģiski, ka tev izdrukāsies true, jo skaitlis 1 ielien 52-bitīgā mainīgā.

 

Kārtējo reizi pareklamēšu linku: What Every Computer Scientist Should Know About Floating-Point Arithmetic. Ja notiek darbošanās ar floatiem/doubļiem, tad tā linka izlasīšana ir obligāta.

Link to comment
Share on other sites

bubu, es nomainīju uz 1152921504606846975, kā tu teici, un viss bija tieši tāpat...

kr4 it works! np

 

tieši tāpēc es cenšos pēc iespējas pārbaudīt/izpildīt pat samērā vnkāršu kodu, jo šad tad tas ko teorētiski iedomājos atšķiras no tā, kas ir praktiski ;)

pat apskatīju šādu debug info abiem šiem skaitļiem

echo decbin(1152921504606846976) . '<br />';  // 1000000000000000000000000000000000000000000000000000000000000
echo decbin(1152921504606846975) . '<br />';  // 111111111111111111111111111111111111111111111111111111111111

bet varbūt vajag savādāku testu? man vnk likās, ka ja es pēc float kasta šo vērtību salīdzinu ar sākotnējo int vērtību un tās sakrīt, tad ar to pietiek, lai secinātu, ka (float) neko nav sabojājis. varbūt tev ir kāda 64bit sistēma, kur šāds float kasts pakāš zīmīgos ciparus?

Link to comment
Share on other sites

Jebkurā gadījumā, es uzskatu, ka ir jālieto (float) pie float un (int) pie integera.

 

Neņemot vērā bubu pieminēto, Tu nevari paredzēt kā (float) nākotnē uzvedīdīsies.

Piemēram, tas var sākt izdot pilnu decimālskaitli, t.i., veseliem skaitļiem, likt .0 galā.

Link to comment
Share on other sites

bubu, tev taisnība! sākot no 53bit sākas prikoli :D

function ev($v) {echo (is_bool($v) ? ($v ? 'true' : 'false') : gettype($v) . ':' . $v) . '<br />';}  // echo val

ini_set('precision', 20);

// pow(2, 40) +/-1
ev((float) 1099511627775);  // double:1099511627775
ev((float) 1099511627776);  // double:1099511627776
ev((float) 1099511627777);  // double:1099511627777

// pow(2, 50) +/-1
ev((float) 1125899906842623);  // double:1125899906842623
ev((float) 1125899906842624);  // double:1125899906842624
ev((float) 1125899906842625);  // double:1125899906842625

// pow(2, 55) +/-1
ev(36028797018963967);  // integer:36028797018963967
ev(36028797018963968);  // integer:36028797018963968
ev(36028797018963969);  // integer:36028797018963969
ev((float) 36028797018963967);  // double:36028797018963968
ev((float) 36028797018963968);  // double:36028797018963968
ev((float) 36028797018963969);  // double:36028797018963968

// pow(2, 60) +/-1
ev(1152921504606846975);  // integer:1152921504606846975
ev(1152921504606846976);  // integer:1152921504606846976
ev(1152921504606846977);  // integer:1152921504606846977
ev((float) 1152921504606846975);  // double:1152921504606846976
ev((float) 1152921504606846976);  // double:1152921504606846976
ev((float) 1152921504606846977);  // double:1152921504606846976
ev(1152921504606846975.0);  // double:1152921504606846976
ev(1152921504606846976.0);  // double:1152921504606846976
ev(1152921504606846977.0);  // double:1152921504606846976

// neskatoties uz to, salīdzināšana joprojām ir "pareiza"
ev(1152921504606846975 == 1152921504606846975.0);  // true

// tagad gan vairs ne ^^
ev((string) 1152921504606846975 == (string) 1152921504606846975.0);  // false

es to pamanīju tikai tad, kad gribēju notestēt qn() kaujas apstākļos (uz mysql bigint)

izrādījās, ka kaut arī salīdzināšana ar tādu pašu int ir true, taču outputojot uz string/file tā vērtība "apaļojas" (kverijā nokļūst nepareiza vērtība). tb šajā brīdī tad beidzot pakāšas tie zīmīgie cipari/biti

 

kārtējo reizi apstiprinās tas, ka viss ir jātestē ;) viens tests neko nedeva, bet cits jau atklāja gļukus...

 

 

update...

function qi($i) {return is_null($i) ? 'NULL' : preg_replace('/[^\d-]/', '', $i);}  // query int val - sagatavo big integer (over 32bit) for mysql query
function qn($n) {return is_null($n) ? 'NULL' : (float) $n;}  // query num val - sagatavo skaitli for mysql query
function qs($s) {return is_null($s) ? 'NULL' : "'" . mysql_real_escape_string($s) . "'";}  // query str val - sagatavo tekstu for mysql query
function go($sSql) {  // mysql query ar error reportingu
$h = mysql_query($sSql) or die('<b>mysql error ' . mysql_errno() . ':</b> ' . mysql_error() . '<br /><b>query:</b> ' . substr($sSql, 0, 1000));
return $h;
}

ini_set('precision', 20);

go('DROP TABLE IF EXISTS t');
go('CREATE TABLE t (i bigint) ENGINE=MyISAM');
go('INSERT t (i) VALUES ' .
'(1152921504606846975),' .  // ar šo vērtību viss ok
'(' . qn(1152921504606846975) . '),' .  // šeit notiek "apaļošanās"
'(' . qi(1152921504606846975) . '),' .  // tagad atkal viss ok
'(123.0000000000)'  // specially for endrju ;)
);
$h = go('SELECT * FROM t');
while ($r = mysql_fetch_object($h)) echo $r->i . '<br />';
/*
1152921504606846975
1152921504606846976
1152921504606846975
123
*/

 

Neņemot vērā bubu pieminēto, Tu nevari paredzēt kā (float) nākotnē uzvedīdīsies.

Piemēram, tas var sākt izdot pilnu decimālskaitli, t.i., veseliem skaitļiem, likt .0 galā.

un hai liek galā, cik nulles grib (kaut vai 10) :D:D:D

Edited by 2easy
Link to comment
Share on other sites

'(123.0000000000)'  // specially for endrju ;)

un hai liek galā, cik nulles grib (kaut vai 10) :D:D:D

Nē, nu ja esi drošs par automātisku typecasting (float->int) iekš SQL, tad ok.

Tikpat labi viņš (SQL) varēja failot ar kļūdu par tipu nesaderību.

Link to comment
Share on other sites

me 2

 

ikdienišķām lietām pilnīgi pietiek ar int. tas bigint jau ir priekš kkādiem kosmiskiem aprēķiniem :D

anyway, labi ka bubu paspīdēja ar savām float zināšanām. vismaz vienu jaunu niansi uzzināju ;)

Edited by 2easy
Link to comment
Share on other sites

kārtējo reizi apstiprinās tas, ka viss ir jātestē ;) viens tests neko nedeva, bet cits jau atklāja gļukus...

Nevis jātestē, bet jadomā ko dari. Ja lieto floatu, tad secinājumi ir acīmredzami, neko testēt nevajag.

Salīdzināšana strādāja, jo droši vien php salīdzinaja to int un float'u kā divus float'us. Tb to int'u nokāstoja uz float'u un tad salīdzināja jau nepareizus skaitļus.

 

ikdienišķām lietām pilnīgi pietiek ar int. tas bigint jau ir priekš kkādiem kosmiskiem aprēķiniem :D

Nu nez, nez.. Kādai firmai, kas aktīvi kautko darbojās, un viss logojās datubāzē, sasniegt 4 miljardus ierakstu pēc neilga laiciņa nav nepavisam nekas kosmisks.

Un ka tik pēc tam nesanāk dārgāk mainīt visu sistēmu (uz int64), nekā laicīgi to jau paredzēt:

http://www.twitpocalypse.com/

http://www.macworld.com/article/141146/2009/06/twitpocalypse_twitter.html

http://www.wow.com/2008/01/16/apparently-you-can-have-too-much-gold/

http://forums.worldofwarcraft.com/thread.html?topicId=20860799964&sid=1

utt..

Link to comment
Share on other sites

Nevis jātestē, bet jadomā ko dari.

tā saucās "praktiskā mācīšanās" :))

dažreiz vnkāršāk ir babakstīties nekā lasīt garas teorijas un iedziļināties tehniskās uzbūves niansēs, lai gan tas, protams, ir ļoti noderīgi

 

Salīdzināšana strādāja, jo droši vien php salīdzinaja to int un float'u kā divus float'us. Tb to int'u nokāstoja uz float'u un tad salīdzināja jau nepareizus skaitļus.

true. es jau ar to iedomājos, bet pagaidīju, lai tu pasaki ^^

 

Nu nez, nez.. Kādai firmai, kas aktīvi kautko darbojās, un viss logojās datubāzē, sasniegt 4 miljardus ierakstu pēc neilga laiciņa nav nepavisam nekas kosmisks.

ja logo nevis failā, bet db (droši vien lai ērtā/ātrāk būtu kko meklēt), tad nekādu id tur tāpat nevajag. id lieto lai selectētu/updeitotu/dzēstu konkrētu rindu, bet logfailu skatās daudzas rindas vienlaikus, neko neupdeito, un dzēš arī daudzas rindas vienlaikus. so whats the point from id here?

 

hmm, mb es pārāk burtiski sapratu "viss logojās datubāzē"? tad forget last paragraph :D

 

Un ka tik pēc tam nesanāk dārgāk mainīt visu sistēmu (uz int64), nekā laicīgi to jau paredzēt:

attiecībā uz mysql, cik dārgi ir pāris "ALTER TABLE t MODIFY id bigint"?

attiecībā uz php nekas nav jāmaina, jo uz 64bit sistēmas šādam int jau ir vajadzīgais izmērs. turklāt get/post parametros šīs vērtības vsp ceļo kā stringi

 

vienīgi tajās valodās, kur ir strikti datu tipi un nav izmantots alias (piemēram, c valodā varētu lietot: typedef int id_t; kur vnk int būtu jānomaina ar int64_t), tur gan nākas repleisot visas vietas, kur ir definēts šis id mainīgais, uz lielāku datu tipu un pēc tam pārkompilēt programmu

 

jā, twitter gan ir labs piemērs! ;)

gj bubu

 

tajā wow vienā int bija sadzīti veseli 3 resursu veidi (gold/silver/copper), tāpēc daudz ātrāk nepietika vietas. vnk wow koderi pārcentās ar data space optimizēšanu :D

Edited by 2easy
Link to comment
Share on other sites

attiecībā uz mysql, cik dārgi ir pāris "ALTER TABLE t MODIFY id bigint"?

Runa nav jau par MySQL, bet par dīvainu php kodu - piemēram, taviem kāstiem uz float'u. Lielākā sistēmā ej un sazin cik laika prasīs iziet cauri visam kodam un atrast visas šādas "gudrās" programmētāju dīvainības...

 

jā, twitter gan ir labs piemērs! ;)

gj bubu

nesaprotu, kur ir problēma? Tas ļoti labi demonstrē, kur noved domāšana, ai man jau ar 2.1 (vai 4.2) miljardiem pietiks visam mūžam..

 

tajā wow vienā int bija sadzīti veseli 3 resursu veidi (gold/silver/copper), tāpēc daudz ātrāk nepietika vietas. vnk wow koderi pārcentās ar data space optimizēšanu :D

Tas ir viens un tas pats resursu vieds - nauda. 100 copperi = 1 silvers, 100 silveri = 1 golds. Tāpat kā lati un santīmi nav divi resursu veidi, bet ir viens un tas pats. Neredzu iemesla glabāt santīmus un latus divos dažādos mainīgajos/laukos

Link to comment
Share on other sites

Runa nav jau par MySQL, bet par dīvainu php kodu - piemēram, taviem kāstiem uz float'u. Lielākā sistēmā ej un sazin cik laika prasīs iziet cauri visam kodam un atrast visas šādas "gudrās" programmētāju dīvainības...

nebija mērķis iegūt float kā tādu, bet gan no datiem "skaitlis" izmest liekos/kaitīgos simbolus, lai tie nenokļūst līdz sql

protams, to var izdarīt ar regulāro izteiksmi kā qi() gadījumā, taču gribējās kko vnkāršāku/ātrāku un izšķīros par labu (float)

http://php.net/manual/en/language.types.string.php

String conversion to numbers

If the string starts with valid numeric data, this will be the value used. Otherwise, the value will be 0

tieši tas, kas man bija vajadzīgs (līdz tam nebiju apskatījis gadījumu ar int64/bigint, jo vēl nebiju to lietojis)

 

es arī mācos rakstīt komentārus, lai citiem būtu vieglāk saprast. varbūt tgd ir progress ;)

qi() - query int64 - sagatavo lielu veselu skaitli (int64) ievietošanai mysql query
qn() - query num - sagatavo skaitli (int/float) ievietošanai mysql query
qs() - query str - sagatavo tekstu (any string) ievietošanai mysql query
<- lai būtu saprotamāk
qi() - query int val - sagatavo big integer (over 32bit) for mysql query
qn() - query num val - sagatavo skaitli for mysql query
qs() - query str val - sagatavo tekstu for mysql query

function qi($i) {return is_null($i) ? 'NULL' : preg_replace('/[^\d-]/', '', $i);}  // query int64 - sagatavo lielu veselu skaitli (int64) ievietošanai mysql query
function qn($n) {return is_null($n) ? 'NULL' : (float) $n;}  // query num - sagatavo skaitli (int/float) ievietošanai mysql query
function qs($s) {return is_null($s) ? 'NULL' : "'" . mysql_real_escape_string($s) . "'";}  // query str - sagatavo tekstu (any string) ievietošanai mysql query

nu jā, un, protams, ir jāzin konteksts, kādā šīs funkcijas tiek lietotas: no ārpuses pienāk dati (user input), kuriem ir jābūt kādā no standarta formātiem int64/skaitlis/teksts, taču tie var tādi nebūt un/vai saturēt nevēlamu/kaitīgu kodu, kas ir jāneitralizē. un tieši to arī dara šīs funkcijas. qi() lieto tikai samērā retos speciālgadījumos. parasti pietiek ar otrām divām funkcijām qn() qs(). so simple! ;)

 

vsp man ir ļoti izdevīgi, ka tu kritizē katru sīkumu. it makes me do better and better... :))

paldies Tev, bubu

Edited by 2easy
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...