38

I know how to obtain the square root of a number using the sqrt function.

How can I obtain the cube root of a number?

15
  • 9
    You mean the cube root, not the "square root with root 3". Commented Aug 7, 2013 at 12:47
  • 8
    You can use pow(), with the power 1/3 Commented Aug 7, 2013 at 12:48
  • 9
    -1: This question was better before. Now it's awful. "please guide me to overload sqrt operator" How about we guide you in creating SO questions? Commented Aug 7, 2013 at 12:52
  • 3
    @Kotte 1/3 in C/C++ is 0, not one third. Commented Aug 7, 2013 at 12:53
  • 1
    @LightnessRacesinOrbit I almost rolled your edit back myself. Your's is a very different, albeit far more reasonable, question. Since it's been answered before, I believe it should be left-as is, and left closed. Commented Aug 7, 2013 at 14:12

11 Answers 11

72

sqrt stands for "square root", and "square root" means raising to the power of 1/2. There is no such thing as "square root with root 2", or "square root with root 3". For other roots, you change the first word; in your case, you are seeking how to perform cube rooting.

Before C++11, there is no specific function for this, but you can go back to first principles:

  • Square root: std::pow(n, 1/2.) (or std::sqrt(n))
  • Cube root: std::pow(n, 1/3.) (or std::cbrt(n) since C++11)
  • Fourth root: std::pow(n, 1/4.)
  • etc.

If you're expecting to pass negative values for n, avoid the std::pow solution β€” it doesn't support negative inputs with fractional exponents, and this is why std::cbrt was added:

std::cout << std::pow(-8, 1/3.) << '\n';  // Output: -nan
std::cout << std::cbrt(-8)      << '\n';  // Output: -2

N.B. That . is really important, because otherwise 1/3 uses integer division and results in 0.

9
  • I mean Sqrt not square,for example sqrt(4)=2; Commented Aug 7, 2013 at 12:52
  • 3
    @HavaDarabi: I don't understand. sqrt stands for "square root" whether you like it or not, and sqrt(4) is 2. Commented Aug 7, 2013 at 12:53
  • 1
    See the this already referenced SO q&a - a solution based on pow does not find the cube-root for negative numbers. It's good to reference the C++11 solution. Net: -1/+1 Commented Aug 7, 2013 at 14:18
  • @RichardSitze: std::cbrt(-8) results in -2. That's why they added it. Commented Aug 7, 2013 at 14:20
  • @LightnessRacesinOrbit It's not the standard library solution that's the problem, it's the `pow' based solution. Commented Aug 7, 2013 at 14:21
8

in C++11 std::cbrt was introduced as part of math library, you may refer

2
include <cmath>
std::pow(n, 1./3.)

Also, in C++11 there is cbrt in the same header.

Math for Dummies.

1
  • I suspect this readily fails for negative numbers. Commented Feb 28, 2021 at 1:21
2

I wrote a code for calculating a cube root with single precision under Visual Studio C++ (x86). This function works, as a rule, faster than the standard function cbrtf() and is almost as accurate β€” the maximum error is about 1 ULP. The function works in the entire range of input values.

ULP β€” Unit of Last Position. That is, this is an expression of the error in units of the least significant binary digit of the mantissa. It is convenient to use for numbers presented in exponential format (including float and double), and is essentially similar to the relative error. For example, correctly rounded values have an error of no more than 0.5 ULP.

_declspec(naked) float _vectorcall cbr(float x)
{
  static const float ct[4] =   // Constants table
  {
    0.333333224f,              // Approximately 1/3
    1.07374182E9f,             // 2^30
    3.0f,                      // 3
    3072.0f                    // 3*2^10
  };
  _asm
  {
    mov ecx,offset ct          // ecx is the address of constants table
    mov ax,0x5555              // ax is approximately coefficient 2^16/3
    vmovss xmm3,[ecx]          // xmm3 = 1/3 approximately
      cbr_sub:                 // Handling of subnormal numbers
    add ecx,4                  // Move the pointer to the next coefficient
    vmovaps xmm1,xmm0          // Duplicate argument x in xmm1
    vmovd edx,xmm0             // edx is a binary representation of x
    vmulss xmm0,xmm0,[ecx]     // xmm0 = x*2^30 - try to normalize x (if needed)
    shr edx,15                 // Get the sign at bit 16 of edx, exponent - at dh
    vucomiss xmm0,xmm1         // Compare x to x*2^30 
    jz cbr_end                 // Do not change the values +-0, +-Inf and NaN
    test dh,dh                 // dh=0 if the number is subnormal
    jz cbr_sub                 // Jump if x is the subnormal number
    mul dx                     // dx is approximately 2/3 of high word |x|
    add dx,0x549B              // Add the "magic" constant
    shl edx,15                 // Form the initial approximation bits
    vmovd xmm0,edx             // xmm0 = y0 - initial approximation for Newton's method
    vmulss xmm2,xmm0,xmm0      // xmm2 = y0^2
    vaddss xmm0,xmm0,xmm0      // xmm0 = 2*y0
    vdivss xmm2,xmm1,xmm2      // xmm2 = x/y0^2
    vaddss xmm0,xmm0,xmm2      // xmm0 = 2*y0+x/y0^2
    vmulss xmm0,xmm0,xmm3      // xmm0 = (2*y0+x/y0^2)/3 = y1
    vmulss xmm2,xmm0,xmm0      // xmm2 = y1^2
    vaddss xmm0,xmm0,xmm0      // xmm0 = 2*y1
    vdivss xmm2,xmm1,xmm2      // xmm2 = x/y1^2
    vaddss xmm0,xmm0,xmm2      // xmm0 = 2*y1+x/y1^2
    vmulss xmm0,xmm0,xmm3      // xmm0 = (2*y1+x/y1^2)/3 = y2
    vmulss xmm2,xmm0,xmm0      // xmm2 = y2^2
    vaddss xmm0,xmm0,xmm0      // xmm0 = 2*y2
    vdivss xmm2,xmm1,xmm2      // xmm2 = x/y2^2
    vaddss xmm0,xmm0,xmm2      // xmm0 = 2*y2+x/y2^2
    vdivss xmm0,xmm0,[ecx+4]   // xmm0 = (2*y2+x/y2^2)/3 = y3 - solution
      cbr_end:                 // Result in xmm0 is done
    ret                        // Return
  }
}
3
  • re; "and is almost as accurate β€” the maximum error is about 1 ULP" please add assume readers know nothing and add a comment what ULP is. Ultimate Lip Pucker is probably wrong :) Commented Aug 7 at 15:01
  • ULP β€” Unit of Last Position. That is, this is an expression of the error in units of the least significant binary digit of the mantissa. It is convenient to use for numbers presented in exponential format (including float and double), and is essentially similar to the relative error. For example, correctly rounded values have an error of no more than 0.5 ULP. Commented Aug 7 at 15:46
  • 1
    Thank you! I really love this answer πŸ‘ Commented Aug 8 at 12:14
1

I use the following. It's twice as fast as cbrt() on an ARM Cortex M7 processor but slightly less accurate. It also has a smaller domain because the operand is squared at the start. The reinterpret_cast operations can be replaced by bit_cast if using a sufficiently recent version of C++.

float fastCubeRootf(float f) noexcept
{
    // NOTE: In IEEE 754, 'f == 0.0' is true if f is 0.0 OR -0.0. The following
    // will return 0.0 if f is 0.0, and -0.0 if f is -0.0

    if (f == 0.0) { return f; }                     // estimating the reciprocal cube root fails if the operand is zero

    // First calculate the approximate value of f^-(2/3).
    // See "Generalising the Fast Reciprocal Square Root Algorithm" by Mike Day, https://arxiv.org/pdf/2307.15600
    const float f2 = f * f;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
    const uint32_t i = *reinterpret_cast<const uint32_t*>(&f2);
    const uint32_t i2 = 0x54B8E38E - i/3;
    const float y = *reinterpret_cast<const float*>(&i2);
#pragma GCC diagnostic pop
    const float z = f2 * y * y * y;
    const float f1 = y * (1.3739948 - z * (0.47285829 - z * 0.092823250));

    // f1 is now an approximation of f^-(2/3). Multiply by f to get an approximation of f^(1/3).
    const float r1 = f1 * f;

    // Do 2 Newton-Raphson iterations to improve the accuracy of the result.
    // To avoid division, instead of dividing by (3 * r^2) we multiply by (f1 * 1/3) because f1 is an approximation of f^-(2/3) and therefore an approximation of 1/r^2.
    const float r2 = r1 - (fcube(r1) - f) * f1 * (1.0/3.0);
    const float ret = r2 - (fcube(r2) - f) * f1 * (1.0/3.0);

    return ret;
}
3
  • What is the acceptable range of input data? Does the function handle negative, subnormal, infinity values correctly? Commented Aug 6 at 9:01
  • I got an answer to my question. Unfortunately, this function does not work correctly with subnormal numbers and infinities. It also has a narrowed range of acceptable input numbers. For example, it cannot calculate the cube root of 6.4e19. Otherwise, the function is good: faster than the standard cbrtf() function, although slower than the implementation I proposed. Commented Aug 7 at 3:55
  • Please add clear explanation of slightly less accurate here, when, how, and the circumstance to not use this. Commented Aug 7 at 15:03
0

Just to point this out, though we can use both ways but

 long long res = pow(1e9, 1.0/3);
 long long res2 = cbrt(1e9);
 cout<<res<<endl;
 cout<<res2<<endl;

returns

999
1000

So, in order to get the correct results with pow function we need to add an offset of 0.5 with the actual number or use a double data type i.e.

long long res = pow(1e9+0.5, 1.0/3)
double res = pow(1e9, 1.0/3)

more detailed explanation here C++ pow unusual type conversion

3
  • 1
    I wouldn't trust cbrt to perform precise calculations as well. Commented Jan 15, 2022 at 13:31
  • Ideally yes, we should do the rounding ourselves, we can simply use double or add an offset as I have pointed out in the answer. Thanks for pointing out :D Commented Jan 16, 2022 at 14:31
  • Please clearly state your meaning of though we can use both ways - me reading this upside down was probably not your meaning intent here. Please differentiate from the referenced linked. Commented Aug 7 at 15:05
-1

The nth root of x is equal to x^(1/n), so use std::pow. But I don't see what this has to with operator overloading.

2
  • 3
    @Hava: sqrt is not an "operator", and you cannot "overload" it to perform a different thing with the same arguments. Your terminology is all wrong. Commented Aug 7, 2013 at 12:55
  • 1
    @HavaDarabi no, you don't Commented Aug 7, 2013 at 12:57
-1

You can try this C algorithm :

// return a number that, when multiplied by itself twice, makes N. 
unsigned cube_root(unsigned n){
    unsigned a = 0, b;
    for (int c = sizeof(unsigned) * CHAR_BIT / 3 * 3 ; c >= 0; c -= 3) {
        a <<= 1;
        b = 3 * a * (a + 1) + 1;
        if (n >> c >= b)
            n -= b << c, ++a;
    }
    return a;
}
1
  • I can also "try" 1 * 45 * 984 but adding a clear explanation to add value of this might be better than that simple statement "You can try this C algorithm" which as it stands is just a declaration - explain the merit of this instead. Commented Aug 7 at 15:10
-2

Actually the round must go for the above solutions to work.

The Correct solution would be

ans = round(pow(n, 1./3.));

1
  • "above solutions" well certainly "above" now that this as been downvoted by others. but that declarative statement about others answers would require you to here add ALL those to explain exactly what you mean. Commented Aug 7 at 15:14
-2

The solution for this problem is

cube_root = pow(n,(float)1/3);

and you should #include <math.h> library file

Older standards of C/C++ don't support cbrt() function.

When we write code like cube_root = pow(n,1/3); the compiler thinks 1/3 = 0 (division problem in C/C++), so you need to do typecasting using (float)1/3 in order to get the correct answer

#include<iostream.h>
#include<conio.h>
#include<math.h>
using namespace std;

int main(){
float n = 64 , cube_root ;
clrscr();
cube_root = pow(n , (float)1/3);
cout<<"cube root = "<<cube_root<<endl;
getch();
return 0;
}

cube root = 4

3
  • Turbo C is not a C compiler, and Turbo C++ is not a C++ compiler. They both predate the first C standard (C89) and C++ standard (C++98) by a long time and aren't valid C or C++ compilers. Turbo C++ is more than a decade older than C++98 so your code doesn't even compile in C++ compilers (there's no iostream.h for you). Besides there's no language called C/C++, they're very different languages and both Turbo products are also different Commented Dec 1, 2019 at 2:21
  • cbrt is a new function in C++11 so even compliant C++98 compilers don't support it, let alone a non-C++ compiler Commented Dec 1, 2019 at 2:22
  • Why use float division and then call a double function? Commented Feb 28, 2021 at 1:22
-3

I would discourage any of the above methods as they didn't work for me. I did pow(64, 1/3.) along with pow(64, 1./3.) but the answer I got was 3
Here's my logic.

ans = pow(n, 1/3.);
if (pow(ans, 3) != n){
   ans++;
}
2
  • this doesn't work. For example for the cube root of 7 this will return 2.9129... instead of 1.9129... which is off by merely just ~52.2% Commented Dec 1, 2019 at 2:08
  • Perhaps instead of "ans++" you should use "ans = nextafter(ans, n)" ? Commented Mar 25 at 10:24

Your Answer

By clicking β€œPost Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.