在 C++ 中实现 double sqrt(double x)

发布于 2024-10-17 13:37:10 字数 314 浏览 5 评论 0原文

在 C++ 中实现 double sqrt(double x) 而不使用 std 库。

这是我在这里看到的一个 Facebook 面试问题。 http://www.glassdoor.com /采访/实现-double-sqrt-double-x-in-C-QTN_87210.htm 关于这个还有其他好主意吗?...

!编辑。!!!(不使用标准库。)

Implement double sqrt(double x) in C++ without using std library.

This is a facebook interview question I saw here. http://www.glassdoor.com/Interview/Implement-double-sqrt-double-x-in-C-QTN_87210.htm
Any other good idea about this?...

!!!Edited.!!!(without using std library.)

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

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

发布评论

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

评论(4

×眷恋的温暖 2024-10-24 13:37:10

请查看此处。这篇 CodeProject 文章比较了 14 种不同的计算平方根的方法。

Look here. This CodeProject article compares 14 different methods for computing the square root.

烛影斜 2024-10-24 13:37:10

两个明显的答案是二分法(半慢)和牛顿拉夫森/莱布尼兹迭代(通常更快)。为了避免破坏任何人的乐趣,我将对这个问题进行重新解释 - 这是使用 Newton-Raphson 技术在 8086 汇编语言中实现整数平方根的实现:

isqrt proc uses di, number:word
;
; uses bx, cx, dx
;
    mov di,number
    mov ax,255
start_loop:
    mov bx,ax
    xor dx,dx
    mov ax,di
    div bx
    add ax,bx
    shr ax,1
    mov cx,ax
    sub cx,bx
    cmp cx,2
    ja  start_loop
    ret
isqrt endp

这有待一些改进 - 它使用 x/2作为对 sqrt(x) 的初始猜测。对于超过 386 条指令,您可以使用 bsr 查找设置为粗略近似 log2x 的最高有效位,并将其除以 2 以获得初始值近似。

OTOH,这确实只对古代处理器有意义。对于自 486(或类似版本)以来具有内置浮点硬件的任何东西,几乎可以肯定 FSQRT 指令将击败它(或几乎任何您可以编写的其他指令)。

The two obvious answers are bisection (semi-slow) and Newton-Raphson/Leibniz iteration (usually faster). To keep from spoiling anybody's fun, I'll do a reinterpret_cast on the question -- here's an implementation of an integer square root in 8086 assembly language using the Newton-Raphson technique:

isqrt proc uses di, number:word
;
; uses bx, cx, dx
;
    mov di,number
    mov ax,255
start_loop:
    mov bx,ax
    xor dx,dx
    mov ax,di
    div bx
    add ax,bx
    shr ax,1
    mov cx,ax
    sub cx,bx
    cmp cx,2
    ja  start_loop
    ret
isqrt endp

This is open to some improvement -- it uses x/2 as its initial guess at the sqrt(x). With 386+ instructions, you can use bsr to find the most significant bit that's set to get a rough approximation of log2x, and divide that by 2 to get your initial approximation.

OTOH, this really only made sense on ancient processors. For anything since the 486 (or so) that has built-in floating point hardware, it's nearly certain that the FSQRT instruction will beat this (or pretty much anything else you can write).

念﹏祤嫣 2024-10-24 13:37:10

这是最天才的 sqrt 实现之一,可以在 wikipedia 上找到。它不是最准确的,但速度非常快。

float fast_sqrt(float number) {
   long i;
   float x2, y;
   const float threehalfs = 1.5F;

   x2 = number * 0.5F;
   y  = number;
   i  = * ( long * ) &y;                     // floating point bit level hacking [sic]
   i  = 0x5f3759df - ( i >> 1 );             // Newton's approximation
   y  = * ( float * ) &i;
   y  = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
   y  = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration
   y  = y * ( threehalfs - ( x2 * y * y ) ); // 3rd iteration

   return 1/y;
}

Here is one of the most genius sqrt implementations which can be found on wikipedia. It is not the most accurate, but extremely fast.

float fast_sqrt(float number) {
   long i;
   float x2, y;
   const float threehalfs = 1.5F;

   x2 = number * 0.5F;
   y  = number;
   i  = * ( long * ) &y;                     // floating point bit level hacking [sic]
   i  = 0x5f3759df - ( i >> 1 );             // Newton's approximation
   y  = * ( float * ) &i;
   y  = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
   y  = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration
   y  = y * ( threehalfs - ( x2 * y * y ) ); // 3rd iteration

   return 1/y;
}
我们的影子 2024-10-24 13:37:10

如果允许我使用 log (ln) 和 exp 那么 exp(log(x)/2) 当然会给我平方根。

假设不是:

如果我们发现 的 sqrt 是 x 并且起始值为 y,那么我们迭代 y->(y+x/y)/2

终止条件要么是 y 与其先前值的接近度,要么是y*y 到 x。

使用 385 作为我的 x 值,我在迭代中获得这些值 (Excel)

1
193
97.49740933
50.7231161
29.15667189
21.1805984
19.67880541
19.62150055
19.62141687
19.62141687

您可以使用“近似”2^(log base 2(x)/2) 作为起点而不是 1。
385 的对数介于 8 和 9 之间,因此如果我们说 8.5,则从 2^4.25 开始。如果我们在 16 和 32 之间做这个线性,那么我们将从 20 开始。

从 20 开始,我只需 4 步即可到达:

20
19.625
19.6214172
19.62141687

但它需要之前的“迭代”来计算近似对数和指数。

If I am allowed to use log (ln) and exp then of course exp(log(x)/2) will give me the square root.

Assuming not:

If our value we find the sqrt of is x and the start value is y then we iterate y->(y+x/y)/2

Terminating condition would either be a proximity of y to its previous value or of y*y to x.

With 385 as my x value I get these values in my iterations (Excel)

1
193
97.49740933
50.7231161
29.15667189
21.1805984
19.67880541
19.62150055
19.62141687
19.62141687

You can use an "approximate" 2^(log base 2(x)/2) as a start point instead of 1.
385 has a log somewhere between 8 and 9, so if we say 8.5 and therefore start with 2^4.25. If we do this linear between 16 and 32 then we would start with 20.

Starting with 20 I get there in just 4 steps:

20
19.625
19.6214172
19.62141687

but it required previous "iterations" to calculate the approximate log and exponential.

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