是否有“双”,“ k”的值,以便`k * k == 3.0`?

发布于 2025-02-04 11:26:16 字数 1275 浏览 1 评论 0原文

是否有类型double的值(IEEE 64位float/binary64),k,以便k * k * k == 3.0? (当然,非理性的数字是“ 3平方根”)

我尝试过:

static constexpr double Sqrt3 = 1.732050807568877293527446341505872366942805253810380628055806;
static_assert(Sqrt3 * Sqrt3 == 3.0);

但是静态断言失败了。

(我猜想下一个较高和下一个较低的浮点数既代表数字平方square to 3.0?rounding之后?还是浮点的解析器是愚蠢的?还是在IEEE标准中可行,但是快速的数学优化正在弄乱它吗?)

我认为数字是正确的:

$ python

>>> N = 1732050807568877293527446341505872366942805253810380628055806
>>> N * N
2999999999999999999999999999999999999999999999999999999999996\
607078976886330406910974461358291614910225958586655450309636

更新

我已经发现:

static_assert(Sqrt3 * Sqrt3 < 3.0); // pass
static_assert(Sqrt3 * Sqrt3 > 2.999999999999999); // pass
static_assert(Sqrt3 * Sqrt3 > 2.9999999999999999); // fail

因此,字面意思必须产生下一个较低的值。

我想我需要检查下一个更高的值。可能会稍微降低表示形式,然后递增Mantissa的最后一点。

更新2

后代:我将其用于SQRT3常数和测试:

static constexpr double Sqrt3 = 1.7320508075688772;
static_assert(0x1.BB67AE8584CAAP+0 == 1.7320508075688772);
static_assert(Sqrt3 * Sqrt3 == 2.9999999999999996);

Is there a value of type double (IEEE 64-bit float / binary64), K, such that K * K == 3.0? (The irrational number is of course "square root of 3")

I tried:

static constexpr double Sqrt3 = 1.732050807568877293527446341505872366942805253810380628055806;
static_assert(Sqrt3 * Sqrt3 == 3.0);

but the static assert fails.

(I'm guessing neither the next higher nor next lower floating-point representable number square to 3.0 after rounding? Or is the parser of the floating point literal being stupid? Or is it doable in IEEE standard but fast math optimizations are messing it up?)

I think the digits are right:

$ python

>>> N = 1732050807568877293527446341505872366942805253810380628055806
>>> N * N
2999999999999999999999999999999999999999999999999999999999996\
607078976886330406910974461358291614910225958586655450309636

Update

I've discovered that:

static_assert(Sqrt3 * Sqrt3 < 3.0); // pass
static_assert(Sqrt3 * Sqrt3 > 2.999999999999999); // pass
static_assert(Sqrt3 * Sqrt3 > 2.9999999999999999); // fail

So the literal must produce the next lower value.

I guess I need to check the next higher value. Could bit-dump the representation maybe and then increment the last bit of the mantissa.

Update 2

For posterity: I wound up going with this for the Sqrt3 constant and the test:

static constexpr double Sqrt3 = 1.7320508075688772;
static_assert(0x1.BB67AE8584CAAP+0 == 1.7320508075688772);
static_assert(Sqrt3 * Sqrt3 == 2.9999999999999996);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

心的憧憬 2025-02-11 11:26:16

答案是否定的;没有这样的k

最接近3的平方根的二进制64值等于7800463371553962&nbsp;×2 -52 。它的广场为:

608472288109550042211586778974444×2 -104

此值并非完全可以表示。 )和3之间,分别等于

608472228881095500226464242424999917056

它介于(3&nbsp; - &nbsp; 2 -51

×2 -104 /sup>,

如您所见,k * k比3 更接近3&nbsp; - &nbsp; - &nbsp; - &nbsp; sup> 比3。操作k * k以3&nbsp; - &nbsp; 2 -51 而不是3。(编译器可能会将k转换为扩展计算的精确格式,但结果仍将为3&nbsp; - &nbsp; 2 -51 转换回二进制64

。 /code>在binary64格式中,我们会发现其平方最接近3&nbsp;+&nbsp; 2 -51 ,这是3个以后的下一个代表值。

此结果不应该太惊讶;通常,将数字增加1 ULP将大约2 ULP递增其正方形,因此,给定一些值x,您有大约50%的机会,有一个k具有与x相同的精度,以便k * k == x

The answer is no; there is no such K.

The closest binary64 value to the actual square root of 3 is equal to 7800463371553962 × 2-52. Its square is:

60847228810955004221158677897444 × 2-104

This value is not exactly representable. It falls between (3 - 2-51) and 3, which are respectively equal to

60847228810955002264642499117056 × 2-104

and

60847228810955011271841753858048 × 2-104

As you can see, K * K is much closer to 3 - 2-51 than it is to 3. So IEEE 754 requires the result of the operation K * K to yield 3 - 2-51, not 3. (The compiler might convert K to an extended-precision format for the calculation, but the result will still be 3 - 2-51 after conversion back to binary64.)

Furthermore, if we go to the next representable value after K in the binary64 format, we will find that its square is closest to 3 + 2-51, which is the next representable value after 3.

This result should not be too surprising; in general, incrementing a number by 1 ulp will increment its square by roughly 2 ulps, so you have about a 50% chance, given some value x, that there is a K with the same precision as x such that K * K == x.

私藏温柔 2025-02-11 11:26:16

C标准不规定默认的舍入模式。尽管它通常是最圆的,即使是沿线的,它也可能是向上圆的,并且某些实现支持更改模式。 In such case, squaring 1.732050807568877193176604123436845839023590087890625 while rounding upward produces exactly 3.

#include <fenv.h>
#include <math.h>
#include <stdio.h>

#pragma STDC FENV_ACCESS ON


int main(void)
{
    volatile double x = 1.732050807568877193176604123436845839023590087890625;
    fesetround(FE_UPWARD);
    printf("%.99g\n", x*x);  // Prints “3”.
}

x is declared volatile to prevent the compiler from computing x*x at compile-有不同的圆形模式的时间。一些编译器不支持#pragma stdc fenv_access,但是一旦删除了#pragma行,可以支持fesetround

The C standard does not dictate the default rounding mode. While it is typically round-to-nearest, ties-to-even, it could be round-upward, and some implementations support changing the mode. In such case, squaring 1.732050807568877193176604123436845839023590087890625 while rounding upward produces exactly 3.

#include <fenv.h>
#include <math.h>
#include <stdio.h>

#pragma STDC FENV_ACCESS ON


int main(void)
{
    volatile double x = 1.732050807568877193176604123436845839023590087890625;
    fesetround(FE_UPWARD);
    printf("%.99g\n", x*x);  // Prints “3”.
}

x is declared volatile to prevent the compiler from computing x*x at compile-time with a different rounding mode. Some compilers do not support #pragma STDC FENV_ACCESS but may support fesetround once the #pragma line is removed.

固执像三岁 2025-02-11 11:26:16

我认为使用Python进行测试是有效的,因为两者都使用IEEE-754表示双打以及对操作的规则。

最接近3平方根的双重双重略低。

>>> Sqrt3 = 3**0.5
>>> Sqrt3*Sqrt3
2.9999999999999996

下一个可用值太高。

>>> import numpy as np
>>> Sqrt3p = np.nextafter(Sqrt3,999)
>>> Sqrt3p*Sqrt3p
3.0000000000000004

如果您可以将差异分开,那就可以了。

>>> Sqrt3*Sqrt3p
3.0

Testing with Python is valid I think, since both use the IEEE-754 representation for doubles along with the rules for operations on same.

The closest possible double to the square root of 3 is slightly low.

>>> Sqrt3 = 3**0.5
>>> Sqrt3*Sqrt3
2.9999999999999996

The next available value is too high.

>>> import numpy as np
>>> Sqrt3p = np.nextafter(Sqrt3,999)
>>> Sqrt3p*Sqrt3p
3.0000000000000004

If you could split the difference, you'd have it.

>>> Sqrt3*Sqrt3p
3.0
尤怨 2025-02-11 11:26:16

在Ruby语言中,float类使用“本机体系结构的双精度浮点表示”,它具有名为prev_floatnext_float的方法让您使用最小的步骤通过不同可能的浮子进行迭代。使用此功能,我能够进行简单的测试,并看到 no double(至少在x86_64 linux上)符合您的标准。 Ruby解释器用C编写,因此我认为我的结果应适用于C double类型。

这是红宝石代码:

x = Math.sqrt(3)
4.times { x = x.prev_float }
9.times do
  puts "%.20f squared is %.20f" % [x, x * x]
  puts "Success!" if x * x == 3
  x = x.next_float
end

和输出:

1.73205080756887630500 squared is 2.99999999999999644729
1.73205080756887652704 squared is 2.99999999999999733546
1.73205080756887674909 squared is 2.99999999999999822364
1.73205080756887697113 squared is 2.99999999999999866773
1.73205080756887719318 squared is 2.99999999999999955591
1.73205080756887741522 squared is 3.00000000000000044409
1.73205080756887763727 squared is 3.00000000000000133227
1.73205080756887785931 squared is 3.00000000000000177636
1.73205080756887808136 squared is 3.00000000000000266454

In the Ruby language, the Float class uses "the native architecture's double-precision floating point representation" and it has methods named prev_float and next_float that let you iterate through different possible floats using the smallest possible steps. Using this, I was able to do a simple test and see that there is no double (at least on x86_64 Linux) that meets your criterion. The Ruby interpreter is written in C, so I think my results should be applicable to the C double type.

Here is the Ruby code:

x = Math.sqrt(3)
4.times { x = x.prev_float }
9.times do
  puts "%.20f squared is %.20f" % [x, x * x]
  puts "Success!" if x * x == 3
  x = x.next_float
end

And the output:

1.73205080756887630500 squared is 2.99999999999999644729
1.73205080756887652704 squared is 2.99999999999999733546
1.73205080756887674909 squared is 2.99999999999999822364
1.73205080756887697113 squared is 2.99999999999999866773
1.73205080756887719318 squared is 2.99999999999999955591
1.73205080756887741522 squared is 3.00000000000000044409
1.73205080756887763727 squared is 3.00000000000000133227
1.73205080756887785931 squared is 3.00000000000000177636
1.73205080756887808136 squared is 3.00000000000000266454
失去的东西太少 2025-02-11 11:26:16

是否有类型的值doublek,因此k * k == 3.0

是的。


k = sqrt(n);k * k * k == n也可能是正确的,即使√n是不合理的。

请注意,ksqrt(n)的结果,作为double,是一个有理数。


  • 各种四舍五入模式:@@ericer

  • k * k * k * k rounds n

示例:roots n:11、14和17平方是n

for (int i = 10; i < 20; i++) {
  double x = sqrt(i);
  double y = x * x;
  printf("%2d %.25g\n", i, y);
}

10 10.00000000000000177635684
11 11
12 11.99999999999999822364316
13 12.99999999999999822364316
14 14
15 15.00000000000000177635684
16 16
17 17
18 17.99999999999999644728632
19 19.00000000000000355271368
  • 不同的精度

而不是53位,带有常见的double,例如使用24个fp数学。代码>。

for (int i = 2; i < 11; i++) {
  float x = sqrtf(i);
  printf("%2d  %.25g\n", i, x*x);
}

 2  1.99999988079071044921875
 3  3
 4  4
 5  5
 6  6.000000476837158203125
 7  6.999999523162841796875
 8  7.999999523162841796875
 9  9
10  10

或说FP数学是用64位完成的。 roots n:5、6和10平方为n

for (int i = 2; i < 11; i++) {
  long double x = sqrtl(i);
  printf("%2d  %.35Lg\n", i, x*x);
}

 2  1.9999999999999999998915797827514496
 3  3.0000000000000000002168404344971009
 4  4
 5  5
 6  6
 7  6.9999999999999999995663191310057982
 8  7.9999999999999999995663191310057982
 9  9
10  10

对于各种精确度,(注意C未指定固定精度),k * k == 3.0是可能的。

  • flt_eval_method == 2

flt_eval_method == 2时,可以在更高的进pessions上进行中间计算,从而影响k*k*k*k*k的产物。

(尚未提出一个很好的简单例子。)

Is there a value of type double, K, such that K * K == 3.0?

Yes.


K = sqrt(n); and K * K == n may be true, even when √n is irrational.

Note that K, the result of sqrt(n), as a double, is a rational number.


  • Various rounding modes: @Eric

  • K * K rounds to n

Example: Roots n: 11, 14 and 17 when squared are n.

for (int i = 10; i < 20; i++) {
  double x = sqrt(i);
  double y = x * x;
  printf("%2d %.25g\n", i, y);
}

10 10.00000000000000177635684
11 11
12 11.99999999999999822364316
13 12.99999999999999822364316
14 14
15 15.00000000000000177635684
16 16
17 17
18 17.99999999999999644728632
19 19.00000000000000355271368
  • Different precision

Rather than 53 bits with common double, say the FP math was done with 24. Roots n: 3, 5 and 10 when squared are n.

for (int i = 2; i < 11; i++) {
  float x = sqrtf(i);
  printf("%2d  %.25g\n", i, x*x);
}

 2  1.99999988079071044921875
 3  3
 4  4
 5  5
 6  6.000000476837158203125
 7  6.999999523162841796875
 8  7.999999523162841796875
 9  9
10  10

or say the FP math was done with 64 bits. Roots n: 5, 6 and 10 when squared are n.

for (int i = 2; i < 11; i++) {
  long double x = sqrtl(i);
  printf("%2d  %.35Lg\n", i, x*x);
}

 2  1.9999999999999999998915797827514496
 3  3.0000000000000000002168404344971009
 4  4
 5  5
 6  6
 7  6.9999999999999999995663191310057982
 8  7.9999999999999999995663191310057982
 9  9
10  10

With various precisions, (note C does not specify a fixed precision), K * K == 3.0 is possible.

  • FLT_EVAL_METHOD == 2

When FLT_EVAL_METHOD == 2, intermediate calculations may be done at higher precession, thus affecting the product of k*k.

(Have yet to come up with a good simple example.)

も让我眼熟你 2025-02-11 11:26:16

sqrt(3)是不合理的,这意味着没有理性的数字k,因此k*k == 3。双重只能表示有理数;因此,没有double k,因此k*k == 3

如果您可以接受一个 close 满足k*k == 3的数字,那么您可以使用std :: nemeric_limits(in <代码>&lt; type_traits&gt; ,如果内存使用),以查看您是否在3个最小间隔内。看起来像:

assert( abs(k*k - 3.) <= abs(k*k + 3.) * std::numeric_limits<double>::epsilon * X);

epsilon是与double可以表示的最小区别。我们按两个值的总和进行比较,以使其幅度与我们要检查的数字保持一致。 X是一个缩放因素,可让您调整所接受的精度。

如果这是一个理论上的问题:否。如果这是一个实际的问题:是的,提高一定程度的精度。

sqrt(3) is irrational, which means that there is no rational number k such that k*k == 3. A double can only represent rational numbers; therefore, there is no double k such that k*k == 3.

If you can accept a number that is close to satisfying k*k == 3, then you can use std::numeric_limits (in <type_traits>, if memory serves) to see if you’re within some minimal interval around 3. It may look like:

assert( abs(k*k - 3.) <= abs(k*k + 3.) * std::numeric_limits<double>::epsilon * X);

Epsilon is the smallest difference from one that double can represent. We scale it by the sum of the two values to compare in order to bring its magnitude in line with the numbers we’re checking. X is a scaling factor that lets you adjust the precision you accept.

If this is a theoretical question: no. If it’s a practical question: yes, up some level of precision.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文