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?
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?
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:
std::pow(n, 1/2.)
(or std::sqrt(n)
)std::pow(n, 1/3.)
(or std::cbrt(n)
since C++11)std::pow(n, 1/4.)
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
.
sqrt
stands for "square root" whether you like it or not, and sqrt(4)
is 2
.
pow
does not find the cube-root for negative numbers. It's good to reference the C++11 solution. Net: -1/+1
std::cbrt(-8)
results in -2
. That's why they added it.
include <cmath>
std::pow(n, 1./3.)
Also, in C++11 there is cbrt
in the same header.
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
}
}
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;
}
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
cbrt
to perform precise calculations as well.
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.
sqrt
is not an "operator", and you cannot "overload" it to perform a different thing with the same arguments. Your terminology is all wrong.
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 * 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.
Actually the round must go for the above solutions to work.
The Correct solution would be
ans = round(pow(n, 1./3.));
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
cbrt
is a new function in C++11 so even compliant C++98 compilers don't support it, let alone a non-C++ compiler
float
division and then call a double
function?
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++;
}