我正在进行数字数据淋浴,它显示数字的数据,如偶数或奇数。 现在我停在了无理数的位置,我该怎么测试呢?
这样的事情:
alert(isIrrational(Math.sqrt(9)));
答案 0 :(得分:3)
这取决于上下文,但您可能想要说明非常接近简单有理数的浮点数应该被识别为合理的,否则它们应该被识别为可能的无理数。您必须选择“非常接近”和“简单有理数”的定义。
对于相对较小的数字(比如100以下的绝对值),你可能会说简单的有理数是具有小分母的数字,例如2/3,比如那些分母小于100的那些。你的“非常接近”的定义可能是差异的绝对大小很小,比如10 ^ -6以下,或者你可能要求数字小于分母平方的1000倍。在大多数情况下,这已经足够了。
对具有小分母的数的有理逼近理论是称为丢番图近似的数论的一部分。您可能使用的一个工具是simple continued fraction扩展数字,例如
pi = 3+1/(7+1/(15+1/(1+1/292+...)))
和e-1=1+1/(1+1/(2+1/(1+1/(1+1/(4+1/(1+1/(1+1/(6+...))).
您可以递归计算这些,但快速耗尽精度。当你截断这样的表达式时,你会得到一个很好的有理逼近,例如pi~3,或pi~22 / 7,pi~355 / 113或e~193 / 71。这些给予候选人有理数和小分母。简单连续分数中的大系数意味着该数字具有良好的有理逼近。
如果对分母使用100的阈值,则某些有理数不会被检测为合理的,例如1/500。但是,您可以将1 / 3.0f识别为理性,并将Math.sqrt(2.0)* Math.sqrt(8.0)识别为拒绝Math.sqrt(2.0)。
我不知道是否有一种标准方法可以确定像6.73241 x 10 ^ 31这样的大浮点数的复杂性。这甚至可能是一个整数,但你没有精确的说法。您可能会说接近平滑整数的数字很简单。平滑意味着素数因子分解中没有大质数。虽然通常很难分解大数字,但考虑平滑数字并不是那么糟糕,因为你只需要测试几个可能的素因子。如果你甚至无法测试附近数字的平滑度,你可以将数字的对数与小素数的对数组合进行比较。这可能意味着大质数不会被识别为有理数,但如果您关心,记录设置素数通常距离平滑数字1,例如2 ** 57885161-1。
在非常大的浮点数和小数之间,您可以使用某种复杂性度量,它使用可能的分子的简单性和可能的分母的简单性的组合。因此,对于10 ^ 6到10 ^ 9之间的数字,您可能会认为您只能容忍最多10个分母,并且您可能要求这些数字之一的差值小于10 ^ -4。
答案 1 :(得分:1)
确定sqrt(rational)
是否合理是非常简单的。方法如下:
将rational
参数写为m/n
m
和n
整数和互质,即gcd(n, m) = 1
。现在假设存在r
的有理平方根m/n
。如果r = s/t
包含s
和t
整数和互质,我们会:
s^2/t^2 = rˆ2 = m/n
或
n * s * s = m * t * t
特别是s * s
会划分m * t * t
,因为s
和t
没有共同的素数,s * s
实际上会划分m
。换句话说,我们将有(1)s * s <= m
和(2)m % (s * s) = 0
(mod操作)。因此,s
的所有候选人都可以使用以下例程轻松计算
S
成为除数的空集合d := 1
。m % (d * d)
= 0,则将d
添加到S
d := d + 1
d * d <= m
转到2 S
同样地,我们可以得出结论t
满足(1)t * t <= n
和(2)n % (t * t) = 0
。我们可以使用与上面相同的例程来计算T
的所有平方除数的集合n
(只需将S
替换为T
,将m
替换为n
{1}}。)
最后,我们必须枚举(s, t)
中的所有对S x T
寻找一对
m * s * s = n * t * t
使用精确整数运算,这是完全可能的。如果找不到对(s, t)
,则sqrt(m/n)
将是不合理的。
示例强>
让我们假装我们不知道sqrt(100/81)
是理性的10/9
,并且让我们使用上面给出的算法推断它:
首先,我们计算D
的平方除数的集合100
。这是一个算法的痕迹:
`d = 1` Yes, `100 % (1 * 1) = 0`
`d = 2` Yes, `100 % (2 * 2) = 0`
`d = 3` No, `100 % (3 * 3) = 1`
`d = 4` No, `100 % (4 * 4) = 4`
`d = 5` Yes, `100 % (5 * 5) = 0`
`d = 6` No, `100 % (6 * 6) = 28`
`d = 7` No, `100 % (7 * 7) = 2`
`d = 8` No, `100 % (8 * 8) = 36`
`d = 9` No, `100 % (9 * 9) = 19`
`d = 10` Yes, `100 % (10 * 10) = 0`
End: `11 * 11 > 100`.
所以,D = {1, 2, 5, 10}
。现在让我们计算T
,计算81
`d = 1`, Yes
`d = 2`, No (remainder = 1)
`d = 3`, Yes
`d = 4`, No (remainder = 1)
`d = 5`, No (remainder = 6)
`d = 6`, No (remainder = 9)
`d = 7`, No (remainder = 32)
`d = 8`, No (remainder = 17)
`d = 9`, Yes
End: `10 * 10 > 81`.
所以,T = {1, 3, 9}
现在我们枚举(s, t)
中的所有对D x T
,并将81 * s * s
与100 * t * t
进行比较。对是:
(1, 1), (2, 1), (5, 1), (10, 1)
(1, 3), (2, 3), (5, 3), (10, 3)
(1, 9), (2, 9), (5, 9), (10, 9)
我们看到最后一个(10,9)满足81 * 10 * 10 = 100 * 9 * 9
。因此sqrt(100/81) = 10/9
。如果选择的例子使得没有一对满足等式,则平方根将是不合理的。
答案 2 :(得分:0)
这是一种可能性。第一步是找到下一个最小和最大的浮点数(这些浮点数是导致prevFloat
和nextFloat
的各种赋值)。之后,我们逐步通过所有可能的有理数,分母低于某个阈值,寻找适合浮点数的东西。如果在耗尽潜在分母之前无法找到分数,则会报告NaN
。该函数最终在O(maxDenom)
中运行。
function asRational(number) {
var maxDenom = 1000,
sign = number < 0 ? "-" : "+",
absVal = Math.abs(number),
integer = Math.floor(absVal),
fractionalPart = absVal-integer,
asBinary = fractionalPart.toString(2),
prevAsBinary = asBinary.replace(/10*$/,function(match) {
return "0"+Array(match.length).join("1");
}),
nextAsBinary = asBinary.replace(/01*$/,function(match) {
return "1"+Array(match.length).join("0");
}),
prevFloat = parseFloat(prevAsBinary,2),
nextFloat = parseFloat(nextAsBinary,2),
numerator = 0;
for ( var denominator = 1 ; denominator <= maxDenom ; denominator++ ) {
while ( numerator < denominator*prevFloat ) {
numerator++;
}
if ( numerator <= denominator*nextFloat ) {
return {
"sign":sign,
"integer":integer,
"numerator":numerator,
"denominator":denominator
};
}
}
return NaN;
}
function rationalToString(rational) {
if ( !! rational ) {
return rational.sign+"("+rational.integer
+"+"+rational.numerator+"/"+rational.denominator+")";
} else {
return "NaN";
}
}
function parseFloat(asString,radix) {
var power = asString.length-asString.indexOf(".")-1,
asFloat = parseInt(asString.replace(".",""),radix);
for ( var i = 0 ; i < power ; i++ ) {
asFloat /= radix;
}
return asFloat;
}
var paras = document.getElementsByTagName("p");
for ( var i = 0 ; i < paras.length ; i++ ) {
paras[i].textContent
= paras[i].id+"="+rationalToString(asRational(eval(paras[i].id)));
}
<html>
<head>
</head>
<body>
<p id="5/3"></p>
<p id="100/999"></p>
<p id="99/1000"></p>
<p id="100/1001"></p>
<p id="1000/10000"></p>
</body>
</html>