Why does parseInt(1/0, 19) return 18?
我在javascript中遇到了一个恼人的问题。
1 2
| > parseInt(1 / 0, 19)
> 18 |
为什么parseInt返回18?
- 有趣。但为什么这对你来说是一个烦人的问题呢?你必须用其他方法来处理无穷大吗?如果是这样,一个if可能会有所帮助。
- 你到底在做什么,要求你要么用19进制数字,要么用零除!?
- @雷托艾尔·埃多克斯1〔1〕。
- 当你对JS感到困惑时,回到这句话,记住整个该死的语言是在不到10天的时间内设计和实现的(根据编写者的说法)。
- 我几乎敢在这里引用泽德·肖关于javascript的话!!)
- 2人认为这个问题很清楚,很具体,能够回答。那么为什么要关闭呢?
- 为什么这个问题被认为是模糊的?这个问题能具体到什么程度?作者要求解释javascript中具体表达式的可观察和可重复行为。
- 常见问题解答:"你应该只根据你面临的实际问题提出实际的、可回答的问题。"这实际上不是你实际面临的一个"恼人的问题",而是一个一直在互联网上流传的不切实际的例子。
- python做同样的事情:int('i',19)==18
- @raytoal 0/0 == NaN返回false,因为NaN == NaN是false也是NaN === NaN返回false。
- @奥伯汉姆斯请不要这么说。你说的是别的东西:int(1/0, 19)养了一只ZeroDivisionError,int('Infinity', 19)养了一只ValueError。如果您认为这类似于JS….
- @奥伯哈姆西,这几乎是同一件事。这个问题是一个很好的例子,说明为什么python的类型系统比javascript的限制性更强——例如,为什么必须显式地将其他类型转换为字符串。
1/0的结果是Infinity。
parseInt将其第一个参数视为字符串,这意味着首先调用Infinity.toString(),生成字符串"Infinity"。因此,它的工作原理与您要求它将以19为基数的"Infinity"转换为十进制时的工作原理相同。
以下是以19为基数的数字及其十进制值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| Base 19 Base 10 (decimal)
---------------------------
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
a 10
b 11
c 12
d 13
e 14
f 15
g 16
h 17
i 18 |
接下来会发生的事情是,parseInt扫描输入"Infinity"以查找在接受第一个I之后可以解析和停止的部分(因为n不是以19为基数的有效数字)。
因此,它的行为就好像您调用了parseInt("I", 19),它通过上表转换为十进制18。
- 那为什么ParseInt(1/0,24)给了我15176378?
- @Mithunsatheesh试试parseInt('Infini',24)。
- @Mithunsatheesh:因为在24进制中,n也是一个有效数字,所以它实际上是做parseInt("Infini", 24)的。
- @Mithunsatheesh:可能是因为在以19为基数的解析过程中,只解析了第一个字符(n不在这个基数的字符列表中)?对于基24,可以解析的字符更多,所以结果更大。
- @Tadeck:是的,因为我们喜欢JavaScript,所以要注意它,以不断地学习新的东西:)+1
- 为什么有人想用这样的语言"编程",我无法理解。
- @弗朗斯波玛:JS本身就很漂亮。实际上,在动态语言中,这里所发生的事情没有一部分是不合理的。
- @乔恩:这个人工制品不是动态语言的结果,而是松散类型的结果。在严格类型化的动态语言中,不会隐式地将无穷大(float)转换为"无穷大"(string),以防止这种愚蠢。
- @利亚恩,这不是含蓄的。parseInt通过调用ToString显式地将要解析的参数转换为字符串。Infinity的正确字符串表示是什么?在我看来,"Infinity"是合理的。但是在任何地方都没有隐式转换。
- parseInt用于解析字符串,而不是调用ToString的任意对象。实际上,传入Infinity(不是字符串)并将其转换为"Infinity"的能力是一种不明显的隐式转换。
- 不能说我会同意这一点。隐式类型转换与自动转换有关,而不是未记录的功能。在C语言中,int到long的自动转换已经有很好的文档记录,但仍然是隐含的。
- @乔恩:这是不明显和令人惊讶的行为,与JS是一种"动态语言"无关。它需要知道,IEEE浮点标准任意地将1/0定义为正无穷大,而不是(更广泛接受、更明显、更不出所料)未定义的值。我相信JS是一种很好的语言,但称这种合理的行为有点像斯德哥尔摩综合症。
- 作为一个物理学家(或数学家),我假设x/0返回undefined,而不是像matdeboard所说的Infinity。
- @Muhammaddalkarouri这种转换不像int到long或者文章的那部分描述的那样,它更接近于调用itoa,当然它不是整数到字符串,而是双精度(可以是Infinity)到字符串
- @马特博德:我同意这是令人惊讶的,但不同意这是不合理的。每个决策都有利弊;对我来说,与IEE754的协议比与知情的非程序员的期望的协议更可取。开发人员已经被训练接受计算机系统模型是"正确的",即使它们与更广泛接受的模型不同,因为它们提供了特定的工程效益。我不希望每个人都同意这种观点,但我也不认为称之为斯德哥尔摩综合症是公平的。
- @伊莎莉亚:我的观点是,暗示并不意味着没有证件。只要自动处理ITOA或其他合适的转换函数而不是由程序员显式调用,那么int到long或int到string或将string转换到F中的TextWriterFormat<'T>都是隐式的。
- 我认为这是两个问题的组合:1)隐式调用toString(),2)基是可选参数
- 非常有趣的话题,有着惊人的解释!:-)而2*parseInt(1/0,19)+6给了你最终的答案…;-)
- 讨论模糊编码。一个人可以用这样的东西赢得"IOJSCC")。
- @Munchybunch——你自己说过"parseInt"是用来解析一个字符串的,正如它名字的"parse"部分所暗示的那样(就像所有著名的JS引用所说的那样),所以如果有人故意传递一个不是字符串的论点,如果他们没有得到他们所期望的结果,那他们就不应该太惊讶。
- 楠也有类似的伎俩
- parseInt是否愿意解析一个参数(其中只有前缀是给定基数中的有效数字),这难道不是"愚蠢"的一部分吗?当输入的数字前缀后面有垃圾时,它不会报告错误和/或返回undefined,而只是忽略它。不幸的是,这是很常见的;PHP和C的atoi()和类似的函数做同样的事情。
事件顺序如下:
- 1/0对Infinity的评价
- parseInt读到Infinity,高兴地注意到I以19为基数是18。
- parseInt忽略字符串的其余部分,因为它无法转换。
请注意,对于任何基>= 19,您都会得到一个结果,但对于低于该值的基则不会。对于基础>= 24,您将得到更大的结果,因为n在该点成为一个有效数字。
- + 1。但对于大于19的碱基,它可能不会停在I处。
- @顺便说一句,如果基地更大,为什么会停在19号?你知道吗,什么是最伟大的基础JS可以Iterpret?
- @Nordvind最大的基数parseInt将接受36,因为英语字母表中有26个字母,并且惯例是使用数字,然后使用字母作为给定基数中的一组有效数字。
- 关于要点2,我可以建议把Infinity改为"Infinity"吗?
要添加到以上答案中:
parseint用于将字符串解析为数字(线索在名称中)。在您的情况下,您根本不想进行任何解析,因为1/0已经是一个数字,所以它是一个奇怪的函数选择。如果你有一个数字(你有),并且想把它转换成一个特定的基数,你应该用带基数的toString代替。
1 2
| var num = 1 / 0;
var numInBase19 = num.toString(19); // returns the string"Infinity" |
添加到以上答案中
parseInt(1/0,19)相当于parseInt("Infinity",19)。
在基数19中,0-9和A-I(or a-i)是有效数字。因此,从"无穷大"开始,它取19进制的I,然后转换成10进制,变成18进制。然后它尝试取下一个字符,即不在基19中的n,因此丢弃下一个字符(根据javascript将字符串转换为数字的行为)
所以,如果你写parseInt("Infinity",19)或parseInt("I",19)或parseInt("I",19)的话,结果是一样的,即18。
现在,如果你写parseInt("I0",19),结果将是342。由于I X 19 (the base)^1 + 0 X 19^0=18 X 19^1 + 0 X 19^0=18 X 19 + 0 X 1=342。
同样,parseInt("I11",19)将导致6518。
即
1 2 3 4 5
| 18 X 19^2 + 1 X 19^1 + 1 X 19^0
= 18 X 19^2 + 1 X 19^1 + 1 X 19^0
= 18 X 361 + 1 X 19 + 1 X 1
= 6498 + 19 + 1
= 6518 |