Changeset 90347 in webkit


Ignore:
Timestamp:
Jul 3, 2011 3:27:12 PM (13 years ago)
Author:
barraclough@apple.com
Message:

Reviewed by Sam Weinig.

https://bugs.webkit.org/show_bug.cgi?id=16652
Firefox and JavaScriptCore differ in Number.toString(integer)

Source/JavaScriptCore:

Our arbitrary radix (2..36) toString conversion is inaccurate.
This is partly because it uses doubles to perform math that requires
higher accuracy, and partly becasue it does not attempt to correctly
detect where to terminate, instead relying on a simple 'epsilon'.

  • runtime/NumberPrototype.cpp:

(JSC::decomposeDouble):

  • helper function to extract sign, exponent, mantissa from IEEE doubles.

(JSC::Uint16WithFraction::Uint16WithFraction):

  • helper class, u16int with infinite precision fraction, used to convert the fractional part of the number to a string.

(JSC::Uint16WithFraction::operator*=):

  • Multiply by a uint16.

(JSC::Uint16WithFraction::operator<):

  • Compare two Uint16WithFractions.

(JSC::Uint16WithFraction::floorAndSubtract):

  • Extract the integer portion of the number, and subtract it (clears the integer portion).

(JSC::Uint16WithFraction::comparePoint5):

  • Compare to 0.5.

(JSC::Uint16WithFraction::sumGreaterThanOne):

  • Passed a second Uint16WithFraction, returns true if the result of adding the two values would be greater than one.

(JSC::Uint16WithFraction::isNormalized):

  • Used by ASSERTs to consistency check internal representation.

(JSC::BigInteger::BigInteger):

  • helper class, unbounded integer value, used to convert the integer part of the number to a string.

(JSC::BigInteger::divide):

  • Divide this value through by a uint32.

(JSC::BigInteger::operator!):

  • test for zero.

(JSC::toStringWithRadix):

  • Performs number to string conversion, with the given radix (2..36).

(JSC::numberProtoFuncToString):

  • Changed to use toStringWithRadix.

Tools:

Added forwarding header.

  • DumpRenderTree/ForwardingHeaders/wtf/StdLibExtras.h: Added.

LayoutTests:

Our arbitrary radix (2..36) toString conversion is inaccurate.
This is partly because it uses doubles to perform math that requires
higher accuracy, and partly becasue it does not attempt to correctly
detect where to terminate, instead relying on a simple 'epsilon'.

  • fast/js/number-toString-expected.txt:
    • Update expected results from FAIL to PASS.
Location:
trunk
Files:
3 added
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r90346 r90347  
     12011-07-01  Gavin Barraclough  <barraclough@apple.com>
     2
     3        Reviewed by Sam Weinig.
     4
     5        https://bugs.webkit.org/show_bug.cgi?id=16652
     6        Firefox and JavaScriptCore differ in Number.toString(integer)
     7
     8        Our arbitrary radix (2..36) toString conversion is inaccurate.
     9        This is partly because it uses doubles to perform math that requires
     10        higher accuracy, and partly becasue it does not attempt to correctly
     11        detect where to terminate, instead relying on a simple 'epsilon'.
     12
     13        * fast/js/number-toString-expected.txt:
     14            - Update expected results from FAIL to PASS.
     15
    1162011-07-03  Robert Hogan  <robert@webkit.org>
    217
  • trunk/LayoutTests/fast/js/number-toString-expected.txt

    r37415 r90347  
    1313PASS (1234.567).toString('1') threw exception RangeError: toString() radix argument must be between 2 and 36.
    1414PASS (1234.567).toString(2) is "10011010010.1001000100100110111010010111100011010101"
    15 FAIL (1234.567).toString(3) should be 1200201.120022100021001021021002202. Was 1200201.1200221000210010210210022012001102222001211021211122102120100010210200200010021222011100022102111111220000120121020202022222012221002020211012221122112000100011101001001002222022012020010220022122022110202002002202222202212010021201212012220021121111000000211200200222000112012112202111102102221120000212111202201022111021100221120010011220020100220021221110002212111200002212221102221002020220001110120021210211010221211001220011121210110000101120102000202011022002220222101010221211000120010022102002210021221002122211021120201111101202110100001121111120122120122110201201222020221011002121022200201210122000022020200001000000221221112200220100222120210020001201202121010200011210020001210210121202022102101110122020100020021222102012012222212121111121121121101212122021001010222201200221200011220111121111111102022222110022222112200020021100202210020012212001001102111111221201020222201000210220121000100220121111222121011110101102001002022021011201200101200001210210121000020121110102110210201010021122012201111111201102.
     15PASS (1234.567).toString(3) is "1200201.120022100021001021021002202"
    1616PASS (1234.567).toString(4) is "103102.21010212322113203111"
    1717PASS (1234.567).toString(4.9) is "103102.21010212322113203111"
    18 FAIL (1234.567).toString(5) should be 14414.240414141414141414. Was 14414.240414141414141414200133011442434031040124330244023124200011304312311324100320310322232334401241444023301301424311402410343440440144234121221004042313214433223312340344421433303403212012234210130444410021313022131212430231.
    19 FAIL (1234.567).toString(6) should be 5414.32224554134430233. Was 5414.3222455413443023323355441432422515541513.
    20 FAIL (1234.567).toString(7) should be 3412.365323661111653. Was 3412.36532366111165250030063220011062625264235022366031355006423562400353351033514604443661233126306354466066240662520033312110222004612542216364300525534333221304150444203141210500162302516210434315152234340326603635461501336242116203314153354651126532105365415116500340501505534144156652030554012465625565161332645334223651145104425554526302023034654600066564512123012525546404216112020364120610144012434116162201243325036164040215120665415201320221662333526204360066016546153511426052250513314566552656441054644406206121320041026316114014115253630016446423605405142254165214403262552251626030533313033165104611045024555541606452033416313565234306516501564212144644341243233643122051150155434522302224566623136452416322220322431013335605243531535621413652665133652130062451466235302643446415425055454112014335430303211500136666226012454111006151346436341034352626526044063562543341162200323461022054312415062224634155133626554162431544055412201624614356014312604122500301.
     18PASS (1234.567).toString(5) is "14414.240414141414141414"
     19PASS (1234.567).toString(6) is "5414.32224554134430233"
     20PASS (1234.567).toString(7) is "3412.365323661111653"
    2121PASS (1234.567).toString(8) is "2322.44223351361524"
    22 FAIL (1234.567).toString(9) should be 1621.50830703723265. Was 1621.5083070372326504286173774837630372060325814027244480051722228818706673584846030433103286816612627827366208288276325176580754400075062801517567437284602545263843732750315621080784308545008584283222604350772412773180455340034636066426282833385401610836270783258424664435241004744657657365186683407728065356026660100085748081087670605167712015320172355227234356630625836518877744754735556703388162760481454444228840887560624068320576104244485122863072653032654487714334203226715161160172353021741242363324818144464202812516280381775507613702585788583424881125807185888538676210831486144562375864261345147383222322272055634547363306683408365573860425234373548873681638548110246868604100746883165721244675751048012126782157878154353713371758462432003183582526011586844378053200827331008624516010554456712807563108347046657674665651131422144550256168047014215677030141443587008105610375340533658384385003266047014066632784512440300865616602765820164258867505802667163243085767301453006274266560838042613666653021737412176552874258.
     22PASS (1234.567).toString(9) is "1621.50830703723265"
    2323PASS (1234.567).toString(10) is "1234.567"
    24 FAIL (1234.567).toString(11) should be a22.62674a0a5885. Was a22.62674a0a58849145684a462507384219787878954737689989a347647680876095a2345860885046031287a9a1694a397131934142026745166a704344773a73700802694683125343988941755546a814849594a364029607aa0771a2447068930aa55775996897257a3855716340286a996939669868425056a42944a4543725202099605343316045838659207562a00519a4023622a82606539a94736645317056aa9482468a996994a347471153a71a8684a881786634929410231554133396466810a1310137999aa9911076821099a20247541213715118123019574636441209452414914a696a2969849328944530a34844533922965306848a95a2189454316192787338072241118032120757808a2588a900a7419391324061a544aa1a74a8a9373669362927a4020a628a7341a920559382a473291439394a52447455278191a0074944991223446a09529857938a8944181884714a37592416309652596060a15950167253414370287593729386550380730aa21059a04131a274936a843348919329612133271998378a57529794259a5644a51915812aa102320721422511533436064026a268a4677401310870620386925a6224540a78a8032945065017470785084793207763a3a02a9449127443659851a98297920300353402081344029399a9121852511105716a9325013222074551a466973999.
    25 FAIL (1234.567).toString(12) should be 86a.697938b17701. Was 86a.697938b1770127290b99.
    26 FAIL (1234.567).toString(13) should be 73c.74a91191a65. Was 73c.74a91191a64cb86850bc08a694340c765979634a010706991c088a61018b29a16a74093795640793846a7520587816ba56405b7a872869b395c336ca519474baa17539169173a880b49c178074ba551a5781a115152793324291b9260b60333573955737845b03a2321a65277a780923b262898597973bc4b669705680a0b1b88b366b6386c96208979c14a9632c516326883522840165b38c8b415b7a339abc6ca7051b0ac70277244a05477b8a0a09cab072a27b920389477b65616831116514419c44512967a92b39ca73ac01c461b6735ca31bcc17aba7a76412a7a599a8c217c6a74a67aa6c4664432065732caa7c24a1856170748647c2b049c19c572323c03301c283b69cb46b09a045b444a4c7c82901656583267697389b318a73b171a18406324a78b5c478a9c67c99c877b107448cac651945570a83220baa4a3048157189845cb66b7361c129cc3016c52c4b858cb0874ca122b8b7ba9333aa946391a24b8c86958968773bc18278022b1ba76b24727c2cca55442697549392a152927139208c12745bc26a5c17432332990a3267915b06331374a7a84b9469c0208358290337c99cb323a9076a284c5b318bc826989c8b8663bc249a9c687395504958825c1a541b08710bb647288ca4c1179cc2ac84761123a7b275910cb7a43c18c293b1c754b01cb9a211767356a626887980b384822c14a57494331946a5.
    27 FAIL (1234.567).toString(14) should be 642.7d1bc2caa757. Was 642.7d1bc2caa75735ccb458a0d0b6bb6131b9114537.
    28 FAIL (1234.567).toString(15) should be 574.87895959596. Was 574.87895959595a4bbac80bc1e90eeb5bc8c18b3dc77a5962116b159d66bbb7bd95a4c7984c63322434615e80235b8a482669a85e97218c41518e00eb898aba463593d3b4d00e7dc1d0343cd27161096dd810593669d1561982bcc35cda2e54c28de7759c1586adc867209b034293039e03bdce29cb6a8be7d65e09844094989a2d53663d122330bc94048d1bd67722a86db068a0679025d78db9312272c8b91671596d75d80c53331eb018579c83115c2d00581db910e8e4cb44c4c958c8d86dd59d55439b7c849da32130ded53a697a26a8dcea6b8ddc2ad047624bba922909d8c2d48460bc33a2e816d9ecde13d6d24ee6589b0ad9d696cc28753b8020ad21e86ac4363914adc4a87139ab188313439cd2ea8622b4bd54033e8a4a6e61a80c8229dc37399d73978d1d3443b31c987e158904214cce785d84e22e2a60623b141292e67575b1d1a050dbccd02c4732638d24b4c226e9dcc1a387cd7d2a1e797e0757a9de108846719aab2999b58669b21ab06cee3ac6e29990781505958595a4ce0be0710c5b2190365a2dbbbc5eea4993665e1d25266de37c19605488a2b1ce054361097e63c08ebbb7de7092476ddb0b52c89470a957b999b34b2bcb730053e89ed48789d9a20405b360d084b3805659900bd8b831852929bb542e45e3836c26c423e8421724619c2a9725e437c96a83484961985ddc2d4d8a060dae117d710c.
     24PASS (1234.567).toString(11) is "a22.62674a0a5885"
     25PASS (1234.567).toString(12) is "86a.697938b17701"
     26PASS (1234.567).toString(13) is "73c.74a91191a65"
     27PASS (1234.567).toString(14) is "642.7d1bc2caa757"
     28PASS (1234.567).toString(15) is "574.87895959596"
    2929PASS (1234.567).toString(16) is "4d2.9126e978d5"
    30 FAIL (1234.567).toString(17) should be 44a.9aeb6faa0da. Was 44a.9aeb6faa0da2c5e88788d0f52d2ebc023ae5494926de55072ee4114fb38ga5258dd24a1ga4250bb32247g582114g92gc99462cbb5d8584a21d09eaadg00dc40ec938ggdb9e2091gf2ac482442fbcbc28cde82aa6e79e6a57af38e51fg176526dabc6549900c8976140bb4f5cd0d9c642bdbb7e7135d0ea35feb5805e7ba97975a1f2fa45f62e774307g760ec230e43064edg517gf7c9c93d24c43bg24094406b0b4792cg54a38f2b3065agg390efe33e7655f0288d30ec6b6cb994961625d18g636bf1g3443c2a9g5dc222c546c417a50b3e74df94d217bgeee8fad1cf5c2517g9e7babecd38b7092fd9cg519g029gf701a829e98g37402bc496dc3g0f1473564b33aeede5cc70ge58778ddad730feef409449acgd2a2bcc1917b797c94ec57eb4g8805e9708c5g57a78626029b5c247ae12gf8e7c54bd8024cfgc63a1f723d295cdf3gdf83gg17736a84614g1f68ddd1e4494f27d61ba5901f2384d6dedc7875b1babb8g09570fa3fd32f197d59fg499729261g8fgbg753ead4dafcff1fa8ef719a694db92a80f535c6128eg5659a68efdggd9b32ec6970e7cb41fbg99af02d38c1egb828407eegcc4cf985c77ggdf5gc5b54a8g7bdd4ag2318gdf3512ea7a41d1be2c665gbc5619342b9200f0gda9cd2c957af6d29gegee7228b7dbae7f6788c4eg4556a9ca2e13e75588g369ba1272a1b4.
    31 FAIL (1234.567).toString(18) should be 3ea.a3cd7102ac. Was 3ea.a3cd7102abf03dd3fcf0535638d9d313eha75b49.
    32 FAIL (1234.567).toString(19) should be 37i.aed102a04d. Was 37i.aed102a04d40782ebh1e2gc7i558c30fbe230dha57019e3a30e434220f7142ab33f6e4h3ec9ha57b474a52a9ddheb151594e7661418if1ggc24h26e6574769g148c278efc63ded13615bf6b1igddig1i6d0ffe64a9faad5b4gf240cd074b5hc3idafec1be77g4cb0755g8a0d652ceg9e749bdah56a2h5d3b94c74ff0b78aidgab693if10ab8h046425137ae5250f04c07dc22ifbda3fgdeh9a6e1d23d5ebga293ge581441eeb07b884197424b0c3gfech7820fbgg95eahdc3aceahci65i823d3h146dd80ieff23bi84bec219ea9he47ig3g309ci1h7f0i0i29bab4b1fhd19f9edf4if1f28a5b0bac87cihe28abbh1f4abegba22geh1c6h52c07e0ci5gi819e41d3d0fdee50h27c8hid03a95gcf4hac16188ae5ii719di85ad3a8fd059aa63b1ge9fc541hf69ee66gf0175b41ca1dhahaa39hc7id7c91dc8d09e7h0id0252532dg493g5f80a209c31f41c92ifh02i23iged06i6cf9777g3a10hif3i3217d32b00fii7ag4c8ee9iadf3201i366b4g23gc505g63c846b5102d5gg86dhh2d8eaf301ac13cg0f45d171ff479g1995f1hc7c7ii1i0b981e2e042b371a68hb64c5fh92hf30fd72e073bf439ae10dg4g739h170ddf394cbea90hh5490fia83d36bigf72a5ecf8cf126d54h7ghdeg5fic0i21db77hf88haefdb12h3222fc5c7d307707h5ceg3i01a17be5c31a5gb9dhad6ca6ica7c4ba4491504b7h21c2d83b2db3fi67ch.
     30PASS (1234.567).toString(17) is "44a.9aeb6faa0da"
     31PASS (1234.567).toString(18) is "3ea.a3cd7102ac"
     32PASS (1234.567).toString(19) is "37i.aed102a04d"
    3333PASS (1234.567).toString(20) is "31e.b6g"
    34 FAIL (1234.567).toString(21) should be 2gg.bj0kf5cfe9. Was 2gg.bj0kf5cfe91hk6fg383b1938ff8d00h4k9295959jcbj9c9282e840b169kji1eg32893afe063f0bbfkef2cbaegca035bf10b2aj3e6f6fg0kg35k8j82j82e08e6bi0c2ie8hhcgc57ih6aegb9bh7g808619k264h6hc29k812a70gk210g315d9bfh7if6h6ck9511b2kfb1fg4ed66gdigb641738d5a65gc748e1b688cigkcif51cb261hd4jhj5h4602e2addbie0d3d5dc26bhkecea961h4ia838e2bc92ag34a370c6ejaf27djiebghch29feekj17gf62g74d0h575g94aekd7kdfcbb55ejbb2e96bhj7b91450jaab24jii3aehaed6141ej3fccj8hfjk34kh5idghfb8d1kh39adaf2ce5eh756ej088gg9ab99fb332158dcd59b8ah108ei3431j6i11k092ciibkh2ih9dgh9b0922119c98684b38846630diejg60k1d93cg6ifk57e54akihbi89kh9h084ckcg5a7iieg6c01e90d09dbaik9b15k9kfj0igh00di8bcei4ifek38heea014f0ei2afa8ib08ii9eg2e0k71d43906f13bac08g9e6f22b76kihca1a13ff0eci4217h784ahgd5789j308bdgfjgekhkjhf6fe43dkih40hb2163i613dd4g1jfcb1ibc4i469ekbc38kh99i93k14ag7ikejfa528c38j90fhab8keai8cccikg5f69749934d2856i5908jh2hh99f5jig8hh2eh4ca8gh19k7h2g0a63hbc96d0kg27ke0759dc8107e63jd0ddkb8fe0kk0a04ciadaib51kf101i364i0ic1gedh145i2ghi4ie4j1agc3fgb5hckjj4ea5eke04hj59ie9e4hc4bce16ghf37g4b7fh3jh43bfc52a81.
    35 FAIL (1234.567).toString(22) should be 2c2.ca9937cak. Was 2c2.ca9937cak1d502399f2hka8a3c87h0kc76fa6j5b.
    36 FAIL (1234.567).toString(23) should be 27f.d0lfjb1a7c. Was 27f.d0lfjb1a7c6cabfj7gee33jdja9fg9cmjg378fhea19cfabg896fi0ab1gl839fil5cg8dj1hbgjagb0ilm88em2l9e3jg8hmm19ebmmjj6fk1l19fg7011c1j6ji3c6bl1lhk3khbl105c2d3ce1j2b3818aml72lch658elc4d1h9d94cj861eg75j0k59fdl596i978be821lgkiml5da72bd3j0h563h6khf70m64d9h2eac46l4a2g335i010hdl0h5h1b61agdhmd7kdmmch05iljadhh10i86lah1ajf4fj7i2m8h18jjf2amd2e66a86ei3j0h77b7kf6j657am1f6imjaaa28f021m9a13icka536c0fa65aalbbliei26cll38ac1cm343h0ec8h0k4mh1kbhla6a9889llj6db07eb9gmfihggd1kaim70gb6l082jcaldg353ae9i35g77fem7bg77k7em4c41fhbejmhhggj4blli3f7510l55l1j0c0h862ci9he2dlaki2j0ieah36d8i3gf3di7h095ajkbd3amglggc5i6ifh4076g436jcc9bc335mbgec23bjgfki54fm9fc105c2g1l9mc8mmgm1j3e8i96hjd38ic5keb8m53kb2kcec18c04369lg97dk660idbijfcfh9ef0g05c41116i1l664900jjf5jgkikl9kkhj6j8clm5h584l2875j4j8c358k8j3f88c4a297cbc818j26a0ihmf21ll6kkfm911ae4e7hb2l5ha85ffdi63hmk97cdd4mfcim97gmhclh43ig2j5ma5c19hle8i2hhlm2gjjmiae30754mb7d0l7881ighhh0c0bfagekm07h344bdli77m5jj97g69aeg8163ed6amgfm039bj2b9ib9aldfa103i83cebh0bgdj8m7l823k2d6h4l8mia9hk673maia22mik4k3l07h02mb9g56lk26g3micj053g.
    37 FAIL (1234.567).toString(24) should be 23a.dee4nj99j. Was 23a.dee4nj99j0fg7c.
    38 FAIL (1234.567).toString(25) should be 1o9.e49999999. Was 1o9.e49999999a1i19mnkg41ei2o2gea06fn7g8e53ag3cddjk7lokdf81mn6ke5jjko1odlbc544d8boici7j3om9ifj3ba7dm584ol0bgfc877n2g.
    39 FAIL (1234.567).toString(26) should be 1lc.ej7fa4pkf. Was 1lc.ej7fa4pkfb5i3961o8k832hm594h8p558gbk836d.
    40 FAIL (1234.567).toString(27) should be 1ij.f8971772k. Was 1ij.f8971772jicqigbgeln3176612hjc2lmdh055b6kqjq9k7aqemi31c999qkjk182nkm6iioqopj2fgjq2ed907f68i4jmomclqe07mfobmbc8e11h2382hd0pmf0pqcq9k80d52g7a8g9h1eg403e3i6jbiq8la8g9512lip2h9npbe6dcfm30ede5n5m6fhk8a9nbo6g5i2k60908hdo838n720ffna61g20g75fklld5k322hljjqpndeeecgnk9a8of8f1h4eddckqm2qmo22c6p21pi9cmdhfb8o97859385dhnad3ci9kkaff3f0g75925d3m76a2ejoddfci8j7jiq185ggin1b97qhhpqabeq3bhilhhqplq7ij2l4hiddo77hoco44fdm89k726p65h3dmm6a0k8a9p6gpbo1bfld7amqpb853pmoa0mkoq0c92dkq9fhb3me7he34o16bkh6enpoed5baa75epf7c609haq7ki14qkmd7o59i2km330q2dji11ndeka8imo99p4l4k5n7e6h53c4b6ddn0nifo4l1cjh7l30d4daql0o9h117g41lb5p8d8f09oi4l1c6k38hdj7d102oh1k08fhk0fcnqomihi86lf9m98hfm04e90ipcojo2lo481b6k5925cma6gjn8pcnqdc936h8n77de6hf9hc46bgpmahjijllcoc7lbdi6mlm2mn5247kbkaejjemg2ehioi75p64b9q7cae046m1b7eqp74348kqmj643hf40o48na9lm2p3k3cf3eall2aqk7p73h5hgq6k82clgn11kdcb150cq5607jpadoonpp5i78a3lmhnbbq4l8325a03hd7m37fl94igi43cgp0g4hgd5hkpk1gijhea508eqbgdgmbbikh9k67d60hne52lc68c4jf491kj8bi691p91d6a4bg1ppkn3cq0h34oc9b2mj33oollqj5p3c47lg83l32j0kep8jn11mo160667p.
    41 FAIL (1234.567).toString(28) should be 1g2.foelqia8e. Was 1g2.foelqia8ebflde2c988l.
    42 FAIL (1234.567).toString(29) should be 1dg.gcog9e05q. Was 1dg.gcog9e05po0nh1nj03cbgo1s4id5kf2fqf8nq7rcokr5r63no6b9hj1gnhjbcc4m6kfc7fde17chdp5qbfqc50f2sqjmqoo74sm9k5lskgpr9r8fd5cn9343kr8115oifrk2g7hnnrm1q1es93b3llrihs93si1s3bcjeqrcpbgi0kahhp3d4gpckqmai7019sicnm99i9ssbc783514d47f6qm4m89p5rd0hpear8p3lr0lcigo23bfa0h1c7e0rjh660r8ef5h68f0qb767c22rnlf3223qcaq9ob0ii69f21q8kj29b29f3rs36f56rksdq9438ci9e16hlg3rqm3mj7gmrfsl5662sg7opi1egbap2orejfjghr6oakhgo34s3mdn3p8b94ipfjo64cmhbicgiqk53b4bosjhmi32p0k1iamfqi967a564srpam1h941f6k6mhnp4bf9dkri5qdq4j5fmkl8obhd2697qc2k1s1ekjcqg7oa8akcfkhlorkmqd4hgkh6i74l1apj80kf666p30fh1q9dg8a8ljoeagcjh39139ofgrelf1f6oc8m6ag0gcip89o71sg8befga8n0kie7o227f7qqi3iejklc31n4mghl24d47j895s56a66g73mkp6s5eg1911e04jdc5lkrrrm0gimnm5rc0eoderkjof545drclphj5l3forgmnibdpo4s463rg9ag4nke52mib07hd26jhba5ip94bp2q05b6njlre33mikb8r61l58eii962i6ao6q8iosok7sih21df1c33m4g33fbbke709spj8m0fdnc0rml6c94prrle4614bs1069kck62g48ke386rbknn2sak70slj4j49o39cs6h7eri3lb4n8d7dsa279moms3qg28n26dhddn9j8ckk697j9kn2lk8oo39p099eo71po4hl6255of7m657folsppcc5g39afqbqf5ds0q97a32kkif0omn62hf58g0638b.
     34PASS (1234.567).toString(21) is "2gg.bj0kf5cfe9"
     35PASS (1234.567).toString(22) is "2c2.ca9937cak"
     36PASS (1234.567).toString(23) is "27f.d0lfjb1a7c"
     37PASS (1234.567).toString(24) is "23a.dee4nj99j"
     38PASS (1234.567).toString(25) is "1o9.e49999999"
     39PASS (1234.567).toString(26) is "1lc.ej7fa4pkf"
     40PASS (1234.567).toString(27) is "1ij.f8971772k"
     41PASS (1234.567).toString(28) is "1g2.foelqia8e"
     42PASS (1234.567).toString(29) is "1dg.gcog9e05q"
    4343PASS (1234.567).toString(30) is "1b4.h09"
    44 FAIL (1234.567).toString(31) should be 18p.hhrfcj3t. Was 18p.hhrfcj3t1k41f3ur475nm0bg1h8gu4g13ce2ne0rm2ir3rpqaee5mf5tgth2o8lguf8e3b88bhpt2r51g78uluu3a1fqftitn46hk0acq4stpemhna1kallplbo232fqtj4ch1mksr0kn38g2g3k9nbttettehjr56st04tcdn6o95guhiqe9a0bcrlmha7ht7e45uet5pk0s3928bjguhhrc4ij98hhpthu95pju4d4097r7ipc1k2b5o8qj9qeck5dfdeqimkp155fh2oe5mfk3abkebaq6j3eubssrjfod3p17is71tqieaf7na99p482sll6jr1oihribth5bg41ha7qd3tenff7g171kfdgut580s2noh9qlq8lckgsiukrt21ongno1jc477rf07cr6d5ujqa7srl1bdkon156619a1o9olmctbiiu1ih28fbjuphcd0ngqijsh8n5h59sfs4qhpdu62jkur6tigkgem50ogh37n3jsrdr4d8h7ta3h84p2iureoimpa31eiott237la8d0b9sqjq9l8ra97m4ldnersbmpun64dl50jf32kop6idibf7bekrr6ppot5utdknbq0lid0fkehoc3ssf6orm3g50h6emfsml0ppc1ae6881duufiuj3e84b6uhon93qk4ame494oclafd1mpprsiaqd8gpi7m5brmq8nrh2nlro7phb7pdli1pb0gfedluh0bjb9ennetsfdjs3u.
     44PASS (1234.567).toString(31) is "18p.hhrfcj3t"
    4545PASS (1234.567).toString(32) is "16i.i4jeiu6l"
    46 FAIL (1234.567).toString(33) should be 14d.inf96rdvm. Was 14d.inf96rdvlmnwci9088vbndq4uf4futpirf3tt6bdnmikf5vptow2lfdo9gm6hbr9bvrb7sld6ceb0nm0e6af6b.
    47 FAIL (1234.567).toString(34) should be 12a.j9fchdtm. Was 12a.j9fchdtm1i0e8edbf0vogn0it8vsx3r8s9s5al8h.
    48 FAIL (1234.567).toString(35) should be 109.jtk4d4d4e. Was 109.jtk4d4d4doflfe7xi169wd6oyjq01vqcl2f150bis1clidgo4vg3nybjteo1lmjwxvahfy6dqnwydgaympbcv0gpgka2bwejgn0u0gutj58og5m4ab2udlvxfofqyjor4tqqrg1ik6nc1elynjm0p43j43691y6cfxirrmynomfo0xt808yft9pevk3ljiwboaq0uyr6h989pn5aexskwpp8kb0hrwe45vomiv7phkl1msuk8tya7aagjndr5fhkia6illwtjqjv8kpg9j1cm9yh60x0udj60cwu5nd12d59p8vg0ws7qvmnwn47sdbxr97o60st8bussl2932ughjiitjna9p6s55bjdkgxeobvk9euc04gu79pna4oqoxcv4522ggbcgo852pn9jayroy86sf2q119hymgrct7gj7gidbi88iow66djcbqg1g5j6fc5umb5fssde5uq3rvc9x0g81eo5ursjb1ptwu18ljskttqiixfmthionnj7l5p7qemqtn9cdr4xnax361l60vistm8pmjifgbh0j9se6rnekyyekn1c80o95ivbpnmewa1ac1p2suh4dkt0p7jmshx5qb92cov6v12wn7dxdr8tit051nctry8yt7jpsfsex4683ywbtcx9cjul52scv1ud7c996cwa1ieshpa4g6ocyvwm786lhhkwsbt0ep0a088xuuomg2hqga2pk7ibsb457ui5cle42t7yj7ugfp2ynivha0bxqs868b5yq59hg3ri3v9b0akxg0xgk3fx4o5pcayb9gv0sm1vhget72g6lp20f1q3i6subc9qkvvytcli037h3w47x9j343wxe53vodb3dyo9q8a4aj4dcysx95k5ose36267be1mdli4tqw7hcj3oaewepe0livh58p1w1vjc3w31m5c4v1ke94qdaml45dulv8gj7k75bwpd97h9emvycbe7akuvjt1v5d37kshsrekjfodf957jnak4agnkbv9993ycb69im.
    49 FAIL (1234.567).toString(36) should be ya.kety9sifl. Was ya.kety9sifklzsakqhbyb9.
     46PASS (1234.567).toString(33) is "14d.inf96rdvm"
     47PASS (1234.567).toString(34) is "12a.j9fchdtm"
     48PASS (1234.567).toString(35) is "109.jtk4d4d4e"
     49PASS (1234.567).toString(36) is "ya.kety9sifl"
    5050PASS (1234.567).toString(37) threw exception RangeError: toString() radix argument must be between 2 and 36.
    5151PASS (1234.567).toString(-1) threw exception RangeError: toString() radix argument must be between 2 and 36.
  • trunk/Source/JavaScriptCore/ChangeLog

    r90324 r90347  
     12011-06-30  Gavin Barraclough  <barraclough@apple.com>
     2
     3        Reviewed by Sam Weinig.
     4
     5        https://bugs.webkit.org/show_bug.cgi?id=16652
     6        Firefox and JavaScriptCore differ in Number.toString(integer)
     7
     8        Our arbitrary radix (2..36) toString conversion is inaccurate.
     9        This is partly because it uses doubles to perform math that requires
     10        higher accuracy, and partly becasue it does not attempt to correctly
     11        detect where to terminate, instead relying on a simple 'epsilon'.
     12
     13        * runtime/NumberPrototype.cpp:
     14        (JSC::decomposeDouble):
     15            - helper function to extract sign, exponent, mantissa from IEEE doubles.
     16        (JSC::Uint16WithFraction::Uint16WithFraction):
     17            - helper class, u16int with infinite precision fraction, used to convert
     18              the fractional part of the number to a string.
     19        (JSC::Uint16WithFraction::operator*=):
     20            - Multiply by a uint16.
     21        (JSC::Uint16WithFraction::operator<):
     22            - Compare two Uint16WithFractions.
     23        (JSC::Uint16WithFraction::floorAndSubtract):
     24            - Extract the integer portion of the number, and subtract it (clears the integer portion).
     25        (JSC::Uint16WithFraction::comparePoint5):
     26            - Compare to 0.5.
     27        (JSC::Uint16WithFraction::sumGreaterThanOne):
     28            - Passed a second Uint16WithFraction, returns true if the result of adding
     29              the two values would be greater than one.
     30        (JSC::Uint16WithFraction::isNormalized):
     31            - Used by ASSERTs to consistency check internal representation.
     32        (JSC::BigInteger::BigInteger):
     33            - helper class, unbounded integer value, used to convert the integer part
     34              of the number to a string.
     35        (JSC::BigInteger::divide):
     36            - Divide this value through by a uint32.
     37        (JSC::BigInteger::operator!):
     38            - test for zero.
     39        (JSC::toStringWithRadix):
     40            - Performs number to string conversion, with the given radix (2..36).
     41        (JSC::numberProtoFuncToString):
     42            - Changed to use toStringWithRadix.
     43
    1442011-07-02  Gavin Barraclough  <barraclough@apple.com>
    245
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r89630 r90347  
    255255                865A30F1135007E100CDB49E /* JSValueInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = 865A30F0135007E100CDB49E /* JSValueInlineMethods.h */; settings = {ATTRIBUTES = (Private, ); }; };
    256256                865F408810E7D56300947361 /* APIShims.h in Headers */ = {isa = PBXBuildFile; fileRef = 865F408710E7D56300947361 /* APIShims.h */; settings = {ATTRIBUTES = (Private, ); }; };
     257                866739D213BFDE710023D87C /* BigInteger.h in Headers */ = {isa = PBXBuildFile; fileRef = 866739D013BFDE710023D87C /* BigInteger.h */; };
     258                866739D313BFDE710023D87C /* Uint16WithFraction.h in Headers */ = {isa = PBXBuildFile; fileRef = 866739D113BFDE710023D87C /* Uint16WithFraction.h */; };
    257259                86676D5211FED9BC004B6863 /* BumpPointerAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 86676D4D11FED55D004B6863 /* BumpPointerAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; };
    258260                86704B4212DB8A8100A9FE7B /* YarrSyntaxChecker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86704B4012DB8A8100A9FE7B /* YarrSyntaxChecker.cpp */; };
     
    942944                865A30F0135007E100CDB49E /* JSValueInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSValueInlineMethods.h; sourceTree = "<group>"; };
    943945                865F408710E7D56300947361 /* APIShims.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APIShims.h; sourceTree = "<group>"; };
     946                866739D013BFDE710023D87C /* BigInteger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BigInteger.h; sourceTree = "<group>"; };
     947                866739D113BFDE710023D87C /* Uint16WithFraction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Uint16WithFraction.h; sourceTree = "<group>"; };
    944948                86676D4D11FED55D004B6863 /* BumpPointerAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BumpPointerAllocator.h; sourceTree = "<group>"; };
    945949                86704B4012DB8A8100A9FE7B /* YarrSyntaxChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = YarrSyntaxChecker.cpp; path = yarr/YarrSyntaxChecker.cpp; sourceTree = "<group>"; };
     
    18411845                                F692A84E0255597D01FF60F7 /* ArrayPrototype.h */,
    18421846                                147B83AA0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h */,
     1847                                866739D013BFDE710023D87C /* BigInteger.h */,
    18431848                                BC7952320E15EB5600A898AB /* BooleanConstructor.cpp */,
    18441849                                BC7952330E15EB5600A898AB /* BooleanConstructor.h */,
     
    20112016                                5D53726D0E1C546B0021E549 /* Tracing.d */,
    20122017                                5D53726E0E1C54880021E549 /* Tracing.h */,
     2018                                866739D113BFDE710023D87C /* Uint16WithFraction.h */,
    20132019                                F692A8850255597D01FF60F7 /* UString.cpp */,
    20142020                                F692A8860255597D01FF60F7 /* UString.h */,
     
    25752581                                14BA7A9813AADFF8005B7C2C /* Heap.h in Headers */,
    25762582                                A76F54A313B28AAB00EF2BCE /* JITWriteBarrier.h in Headers */,
     2583                                866739D213BFDE710023D87C /* BigInteger.h in Headers */,
     2584                                866739D313BFDE710023D87C /* Uint16WithFraction.h in Headers */,
    25772585                        );
    25782586                        runOnlyForDeploymentPostprocessing = 0;
  • trunk/Source/JavaScriptCore/runtime/NumberPrototype.cpp

    r88587 r90347  
    2323#include "NumberPrototype.h"
    2424
     25#include "BigInteger.h"
    2526#include "Error.h"
    2627#include "JSFunction.h"
    2728#include "JSString.h"
    2829#include "Operations.h"
     30#include "Uint16WithFraction.h"
    2931#include "dtoa.h"
    3032#include <wtf/Assertions.h>
     
    112114}
    113115
     116// The largest finite floating point number is 1.mantissa * 2^(0x7fe-0x3ff).
     117// Since 2^N in binary is a one bit followed by N zero bits. 1 * 2^3ff requires
     118// at most 1024 characters to the left of a decimal point, in base 2 (1025 if
     119// we include a minus sign). For the fraction, a value with an exponent of 0
     120// has up to 52 bits to the right of the decimal point. Each decrement of the
     121// exponent down to a minimum of -0x3fe adds an additional digit to the length
     122// of the fraction. As such the maximum fraction size is 1075 (1076 including
     123// a point). We pick a buffer size such that can simply place the point in the
     124// center of the buffer, and are guaranteed to have enough space in each direction
     125// fo any number of digits an IEEE number may require to represent.
     126typedef char RadixBuffer[2180];
     127
     128// Mapping from integers 0..35 to digit identifying this value, for radix 2..36.
     129static const char* const radixDigits = "0123456789abcdefghijklmnopqrstuvwxyz";
     130
     131static char* toStringWithRadix(RadixBuffer& buffer, double number, unsigned radix)
     132{
     133    ASSERT(isfinite(number));
     134    ASSERT(radix >= 2 && radix <= 36);
     135
     136    // Position the decimal point at the center of the string, set
     137    // the startOfResultString pointer to point at the decimal point.
     138    char* decimalPoint = buffer + sizeof(buffer) / 2;
     139    char* startOfResultString = decimalPoint;
     140
     141    // Extract the sign.
     142    bool isNegative = number < 0;
     143    if (signbit(number))
     144        number = -number;
     145    double integerPart = floor(number);
     146
     147    // We use this to test for odd values in odd radix bases.
     148    // Where the base is even, (e.g. 10), to determine whether a value is even we need only
     149    // consider the least significant digit. For example, 124 in base 10 is even, because '4'
     150    // is even. if the radix is odd, then the radix raised to an integer power is also odd.
     151    // E.g. in base 5, 124 represents (1 * 125 + 2 * 25 + 4 * 5). Since each digit in the value
     152    // is multiplied by an odd number, the result is even if the sum of all digits is even.
     153    //
     154    // For the integer portion of the result, we only need test whether the integer value is
     155    // even or odd. For each digit of the fraction added, we should invert our idea of whether
     156    // the number is odd if the new digit is odd.
     157    //
     158    // Also initialize digit to this value; for even radix values we only need track whether
     159    // the last individual digit was odd.
     160    bool integerPartIsOdd = integerPart <= static_cast<double>(0x1FFFFFFFFFFFFFull) && static_cast<int64_t>(integerPart) & 1;
     161    ASSERT(integerPartIsOdd == static_cast<bool>(fmod(integerPart, 2)));
     162    bool isOddInOddRadix = integerPartIsOdd;
     163    uint32_t digit = integerPartIsOdd;
     164
     165    // Check if the value has a fractional part to convert.
     166    double fractionPart = number - integerPart;
     167    if (fractionPart) {
     168        // Write the decimal point now.
     169        *decimalPoint = '.';
     170
     171        // Higher precision representation of the fractional part.
     172        Uint16WithFraction fraction(fractionPart);
     173
     174        bool needsRoundingUp = false;
     175        char* endOfResultString = decimalPoint + 1;
     176
     177        // Calculate the delta from the current number to the next & previous possible IEEE numbers.
     178        double nextNumber = nextafter(number, std::numeric_limits<double>::infinity());
     179        double lastNumber = nextafter(number, -std::numeric_limits<double>::infinity());
     180        ASSERT(isfinite(nextNumber) && !signbit(nextNumber));
     181        ASSERT(isfinite(lastNumber) && !signbit(lastNumber));
     182        double deltaNextDouble = nextNumber - number;
     183        double deltaLastDouble = number - lastNumber;
     184        ASSERT(isfinite(deltaNextDouble) && !signbit(deltaNextDouble));
     185        ASSERT(isfinite(deltaLastDouble) && !signbit(deltaLastDouble));
     186
     187        // We track the delta from the current value to the next, to track how many digits of the
     188        // fraction we need to write. For example, if the value we are converting is precisely
     189        // 1.2345, so far we have written the digits "1.23" to a string leaving a remainder of
     190        // 0.45, and we want to determine whether we can round off, or whether we need to keep
     191        // appending digits ('4'). We can stop adding digits provided that then next possible
     192        // lower IEEE value is further from 1.23 than the remainder we'd be rounding off (0.45),
     193        // which is to say, less than 1.2255. Put another way, the delta between the prior
     194        // possible value and this number must be more than 2x the remainder we'd be rounding off
     195        // (or more simply half the delta between numbers must be greater than the remainder).
     196        //
     197        // Similarly we need track the delta to the next possible value, to dertermine whether
     198        // to round up. In almost all cases (other than at exponent boundaries) the deltas to
     199        // prior and subsequent values are identical, so we don't need track then separately.
     200        if (deltaNextDouble != deltaLastDouble) {
     201            // Since the deltas are different track them separately. Pre-multiply by 0.5.
     202            Uint16WithFraction halfDeltaNext(deltaNextDouble, 1);
     203            Uint16WithFraction halfDeltaLast(deltaLastDouble, 1);
     204
     205            while (true) {
     206                // examine the remainder to determine whether we should be considering rounding
     207                // up or down. If remainder is precisely 0.5 rounding is to even.
     208                int dComparePoint5 = fraction.comparePoint5();
     209                if (dComparePoint5 > 0 || (!dComparePoint5 && (radix & 1 ? isOddInOddRadix : digit & 1))) {
     210                    // Check for rounding up; are we closer to the value we'd round off to than
     211                    // the next IEEE value would be?
     212                    if (fraction.sumGreaterThanOne(halfDeltaNext)) {
     213                        needsRoundingUp = true;
     214                        break;
     215                    }
     216                } else {
     217                    // Check for rounding down; are we closer to the value we'd round off to than
     218                    // the prior IEEE value would be?
     219                    if (fraction < halfDeltaLast)
     220                        break;
     221                }
     222
     223                ASSERT(endOfResultString < (buffer + sizeof(buffer) - 1));
     224                // Write a digit to the string.
     225                fraction *= radix;
     226                digit = fraction.floorAndSubtract();
     227                *endOfResultString++ = radixDigits[digit];
     228                // Keep track whether the portion written is currently even, if the radix is odd.
     229                if (digit & 1)
     230                    isOddInOddRadix = !isOddInOddRadix;
     231
     232                // Shift the fractions by radix.
     233                halfDeltaNext *= radix;
     234                halfDeltaLast *= radix;
     235            }
     236        } else {
     237            // This code is identical to that above, except since deltaNextDouble != deltaLastDouble
     238            // we don't need to track these two values separately.
     239            Uint16WithFraction halfDelta(deltaNextDouble, 1);
     240
     241            while (true) {
     242                int dComparePoint5 = fraction.comparePoint5();
     243                if (dComparePoint5 > 0 || (!dComparePoint5 && (radix & 1 ? isOddInOddRadix : digit & 1))) {
     244                    if (fraction.sumGreaterThanOne(halfDelta)) {
     245                        needsRoundingUp = true;
     246                        break;
     247                    }
     248                } else if (fraction < halfDelta)
     249                    break;
     250
     251                ASSERT(endOfResultString < (buffer + sizeof(buffer) - 1));
     252                fraction *= radix;
     253                digit = fraction.floorAndSubtract();
     254                if (digit & 1)
     255                    isOddInOddRadix = !isOddInOddRadix;
     256                *endOfResultString++ = radixDigits[digit];
     257
     258                halfDelta *= radix;
     259            }
     260        }
     261
     262        // Check if the fraction needs rounding off (flag set in the loop writing digits, above).
     263        if (needsRoundingUp) {
     264            // Whilst the last digit is the maximum in the current radix, remove it.
     265            // e.g. rounding up the last digit in "12.3999" is the same as rounding up the
     266            // last digit in "12.3" - both round up to "12.4".
     267            while (endOfResultString[-1] == radixDigits[radix - 1])
     268                --endOfResultString;
     269
     270            // Radix digits are sequential in ascii/unicode, except for '9' and 'a'.
     271            // E.g. the first 'if' case handles rounding 67.89 to 67.8a in base 16.
     272            // The 'else if' case handles rounding of all other digits.
     273            if (endOfResultString[-1] == '9')
     274                endOfResultString[-1] = 'a';
     275            else if (endOfResultString[-1] != '.')
     276                ++endOfResultString[-1];
     277            else {
     278                // One other possibility - there may be no digits to round up in the fraction
     279                // (or all may be been rounded off already), in which case we may need to
     280                // round into the integer portion of the number. Remove the decimal point.
     281                --endOfResultString;
     282                // In order to get here there must have been a non-zero fraction, in which case
     283                // there must be at least one bit of the value's mantissa not in use in the
     284                // integer part of the number. As such, adding to the integer part should not
     285                // be able to lose precision.
     286                ASSERT((integerPart + 1) - integerPart == 1);
     287                ++integerPart;
     288            }
     289        } else {
     290            // We only need to check for trailing zeros if the value does not get rounded up.
     291            while (endOfResultString[-1] == '0')
     292                --endOfResultString;
     293        }
     294
     295        *endOfResultString = '\0';
     296        ASSERT(endOfResultString < buffer + sizeof(buffer));
     297    } else
     298        *decimalPoint = '\0';
     299
     300    BigInteger units(integerPart);
     301
     302    // Always loop at least once, to emit at least '0'.
     303    do {
     304        ASSERT(buffer < startOfResultString);
     305
     306        // Read a single digit and write it to the front of the string.
     307        // Divide by radix to remove one digit from the value.
     308        digit = units.divide(radix);
     309        *--startOfResultString = radixDigits[digit];
     310    } while (!!units);
     311
     312    // If the number is negative, prepend '-'.
     313    if (isNegative)
     314        *--startOfResultString = '-';
     315    ASSERT(buffer <= startOfResultString);
     316
     317    return startOfResultString;
     318}
     319
    114320// toExponential converts a number to a string, always formatting as an expoential.
    115321// This method takes an optional argument specifying a number of *decimal places*
     
    210416    DecimalNumber number(x, RoundingSignificantFigures, significantFigures);
    211417    // If number is in the range 1e-6 <= x < pow(10, significantFigures) then format
    212     // as decimal. Otherwise, format the number as an exponential.  Decimal format
     418    // as decimal. Otherwise, format the number as an exponential. Decimal format
    213419    // demands a minimum of (exponent + 1) digits to represent a number, for example
    214420    // 1234 (1.234e+3) requires 4 digits. (See ECMA-262 15.7.4.7.10.c)
     
    239445        return JSValue::encode(jsString(exec, v.toString(exec)));
    240446
    241     static const char* const digits = "0123456789abcdefghijklmnopqrstuvwxyz";
    242 
    243447    // Fast path for number to character conversion.
    244448    if (radix == 36) {
     
    247451            if (static_cast<unsigned>(x) < 36) { // Exclude negatives
    248452                JSGlobalData* globalData = &exec->globalData();
    249                 return JSValue::encode(globalData->smallStrings.singleCharacterString(globalData, digits[x]));
     453                return JSValue::encode(globalData->smallStrings.singleCharacterString(globalData, radixDigits[x]));
    250454            }
    251455        }
     
    255459        return throwVMError(exec, createRangeError(exec, "toString() radix argument must be between 2 and 36"));
    256460
    257     // INT_MAX results in 1024 characters left of the dot with radix 2
    258     // give the same space on the right side. safety checks are in place
    259     // unless someone finds a precise rule.
    260     char s[2048 + 3];
    261     const char* lastCharInString = s + sizeof(s) - 1;
    262461    double x = v.uncheckedGetNumber();
    263462    if (!isfinite(x))
    264463        return JSValue::encode(jsString(exec, UString::number(x)));
    265464
    266     bool isNegative = x < 0.0;
    267     if (isNegative)
    268         x = -x;
    269 
    270     double integerPart = floor(x);
    271     char* decimalPoint = s + sizeof(s) / 2;
    272 
    273     // convert integer portion
    274     char* p = decimalPoint;
    275     double d = integerPart;
    276     do {
    277         int remainderDigit = static_cast<int>(fmod(d, radix));
    278         *--p = digits[remainderDigit];
    279         d /= radix;
    280     } while ((d <= -1.0 || d >= 1.0) && s < p);
    281 
    282     if (isNegative)
    283         *--p = '-';
    284     char* startOfResultString = p;
    285     ASSERT(s <= startOfResultString);
    286 
    287     d = x - integerPart;
    288     p = decimalPoint;
    289     const double epsilon = 0.001; // TODO: guessed. base on radix ?
    290     bool hasFractionalPart = (d < -epsilon || d > epsilon);
    291     if (hasFractionalPart) {
    292         *p++ = '.';
    293         do {
    294             d *= radix;
    295             const int digit = static_cast<int>(d);
    296             *p++ = digits[digit];
    297             d -= digit;
    298         } while ((d < -epsilon || d > epsilon) && p < lastCharInString);
    299     }
    300     *p = '\0';
    301     ASSERT(p < s + sizeof(s));
    302 
    303     return JSValue::encode(jsString(exec, startOfResultString));
     465    RadixBuffer s;
     466    return JSValue::encode(jsString(exec, toStringWithRadix(s, x, radix)));
    304467}
    305468
  • trunk/Source/JavaScriptCore/wtf/MathExtras.h

    r89943 r90347  
    3232#include <limits>
    3333#include <stdlib.h>
     34#include <wtf/StdLibExtras.h>
    3435
    3536#if OS(SOLARIS)
     
    260261#endif
    261262
     263// decompose 'number' to its sign, exponent, and mantissa components.
     264// The result is interpreted as:
     265//     (sign ? -1 : 1) * pow(2, exponent) * (mantissa / (1 << 52))
     266inline void decomposeDouble(double number, bool& sign, int32_t& exponent, uint64_t& mantissa)
     267{
     268    ASSERT(isfinite(number));
     269
     270    sign = signbit(number);
     271
     272    uint64_t bits = WTF::bitwise_cast<uint64_t>(number);
     273    exponent = (static_cast<int32_t>(bits >> 52) & 0x7ff) - 0x3ff;
     274    mantissa = bits & 0xFFFFFFFFFFFFFull;
     275
     276    // Check for zero/denormal values; if so, adjust the exponent,
     277    // if not insert the implicit, omitted leading 1 bit.
     278    if (exponent == -0x3ff)
     279        exponent = mantissa ? -0x3fe : 0;
     280    else
     281        mantissa |= 0x10000000000000ull;
     282}
     283
    262284#endif // #ifndef WTF_MathExtras_h
  • trunk/Tools/ChangeLog

    r90341 r90347  
     12011-07-02  Gavin Barraclough  <barraclough@apple.com>
     2
     3        Reviewed by Sam Weinig.
     4
     5        https://bugs.webkit.org/show_bug.cgi?id=16652
     6        Firefox and JavaScriptCore differ in Number.toString(integer)
     7
     8        Added forwarding header.
     9
     10        * DumpRenderTree/ForwardingHeaders/wtf/StdLibExtras.h: Added.
     11
    1122011-04-02  Robert Hogan  <robert@webkit.org>
    213
Note: See TracChangeset for help on using the changeset viewer.