Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Dec 24, 2020. It is now read-only.
/pcjs.v1Public archive

Commit377d98e

Browse files
committed
More conversion info on the evils Number.parseInt() and the benefits of Math.trunc()
1 parentc1be892 commit377d98e

File tree

1 file changed

+41
-17
lines changed

1 file changed

+41
-17
lines changed

‎modules/devices/lib/stdio.js‎

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -430,12 +430,36 @@ class StdIO extends NumIO {
430430

431431
case'd':
432432
/*
433-
* We could use "arg |= 0", but there may be some value to supporting integers > 32 bits.
433+
* I could use "arg |= 0", but there may be some value to supporting integers > 32 bits,
434+
* so I use Math.trunc() instead. Bit-wise operators also mask a lot of evils, by converting
435+
* complete nonsense into zero, so while I'm ordinarily a fan, that's not desirable here.
434436
*
435-
* Also, unlike the 'X' and 'x' hexadecimal cases, there's no need to explicitly check for string
436-
* arguments, because Math.trunc() automatically coerces any string value to a (decimal) number.
437+
* Other (hidden) advantages of Math.trunc(): it automatically converts strings, it honors
438+
* numeric prefixes (the traditional "0x" for hex and the newer "0o" for octal), and it returns
439+
* NaN if the ENTIRE string cannot be converted.
440+
*
441+
* parseInt(), which would seem to be the more logical choice here, doesn't understand "0o",
442+
* doesn't return NaN if non-digits are embedded in the string, and doesn't behave consistently
443+
* across all browsers when parsing older octal values with a leading "0"; Math.trunc() doesn't
444+
* recognize those octal values either, but I'm OK with that, as long as it CONSISTENTLY doesn't
445+
* recognize them.
446+
*
447+
* That last problem is why some recommend that you ALWAYS pass a radix to parseInt(), but that
448+
* forces you to parse the string first and determine the proper radix; otherwise, you end up
449+
* with NEW inconsistencies. For example, if radix is 10 and the string is "0x10", the result
450+
* is zero, since parseInt() happily stops parsing when it reaches the first non-radix 10 digit.
437451
*/
438452
arg=Math.trunc(arg);
453+
/*
454+
* Before falling into the decimal floating-point code, we take this opportunity to convert
455+
* the precision value, if any, to the minimum number of digits to print. Which basically means
456+
* setting zeroPad to true, width to precision, and then unsetting precision.
457+
*/
458+
if(precision>=0){
459+
zeroPad=true;
460+
if(width<precision)width=precision;
461+
precision=-1;
462+
}
439463
/* falls through */
440464

441465
case'f':
@@ -474,9 +498,11 @@ class StdIO extends NumIO {
474498

475499
case's':
476500
/*
477-
* 's' includes some non-standard behavior, such as coercing non-strings to strings first.
501+
* 's' includes some non-standard benefits, such as coercing non-strings to strings first;
502+
* we know undefined and null values don't have a toString() method, but hopefully everything
503+
* else does.
478504
*/
479-
if(arg!==undefined){
505+
if(arg!=undefined){
480506
if(typeofarg!="string"){
481507
arg=arg.toString();
482508
}
@@ -501,25 +527,23 @@ class StdIO extends NumIO {
501527

502528
case'X':
503529
ach=StdIO.HexUpperCase;
504-
// if (hash) prefix = "0X"; // I don't like that %#X uppercasesboth the prefix and the value
530+
// if (hash) prefix = "0X"; // I don't like that %#X uppercasesBOTH the prefix and the value
505531
/* falls through */
506532

507533
case'x':
508534
s="";
509535
if(!radix)radix=16;
510536
if(!prefix&&hash)prefix="0x";
511537
if(!ach)ach=StdIO.HexLowerCase;
512-
if(typeofarg=="string"){
513-
/*
514-
* Since we're advised to ALWAYS pass a radix to parseInt(), we must detect explicitly
515-
* hex values ourselves, because using a radix of 10 with any "0x..." value always returns 0.
516-
*
517-
* And if the value CAN be interpreted as decimal, then we MUST interpret it as decimal, because
518-
* we have sprintf() calls in /modules/pcx86/lib/testmon.js that depend on this code to perform
519-
* decimal to hex conversion. We're going to make our own rules here, since passing numbers in
520-
* string form isn't part of the sprintf "spec".
521-
*/
522-
arg=Number.parseInt(arg,arg.match(/(^0x|[a-f])/i)?16 :10);
538+
/*
539+
* For all the same reasons articulated above (for type 'd'), we pass the arg through Math.trunc(),
540+
* and we honor precision, if any, as the minimum number of digits to print.
541+
*/
542+
arg=Math.trunc(arg);
543+
if(precision>=0){
544+
zeroPad=true;
545+
if(width<precision)width=precision;
546+
precision=-1;
523547
}
524548
if(zeroPad&&!width){
525549
/*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp