Oh, this site could be more fluid. I think this thing slows down on multiplications and speeds up on divisions. This why it is nothing today. It speed very much on fsqrt, so I don't know this is very well documented, but if the new ones (my is old) do all things in all speed, may you will see the real difference between they. Including bit shift.
#include <iomanip>
#include <cmath>
#include <chrono>
#include <limits>
#include <vector>
#include <random>
#include <algorithm>
#include <numeric>
#include <iostream>
// Constants
const int MAX_ITERATIONS = 1000000;
const double precision = 1e-3; // Adjusted precision
bool showNewtonIteration = true;
bool showAnothersIteration = true;
struct IterationData {
double number;
double sqrtResult;
int iterations;
};
// Optimized Newton's method for finding the square root
double newtonSqrt(double number, double precision, int& iterations, bool showIteration) {
if (number == 0) return 0;
double guess = number * 0.5; // Starting guess
double nextGuess = 0;
iterations = 0;
while (true) {
if (std::fabs(guess - nextGuess) < precision) {
break;
}
iterations++;
if (showIteration && showNewtonIteration) {
std::cout << "Newton's method - ";
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10) << guess << " and more...";
if (std::fabs(guess - nextGuess) < precision) {
std::cout << " reached desired precision";
}
std::cout << std::endl;
}
nextGuess = guess;
guess = 0.5 * (guess + number / guess);
}
return nextGuess;
}
// Iterative another's method with dynamic initial approximation
double anothersMethod(double number, double precision, int& iterations, bool showIteration) {
double f = number * 0.5; // Using the initial approximation
double prev_f = 0;
iterations = 0;
while (true) {
// Check if the value converges within the given precision
if (std::fabs(f - prev_f) < precision) {
break;
}
iterations++;
if (showIteration && showAnothersIteration) {
std::cout << "Another's method - ";
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10) << f << " and more...";
if (std::fabs(f - prev_f) < precision) {
std::cout << " reached desired precision";
}
std::cout << std::endl;
}
prev_f = f;
// New formula to improve the estimate
f = f - (f * f - number) / (f + number / f);
}
return f;
}
// Union to manipulate double as an integer (bit manipulation)
union {
double value;
uint64_t bits;
} db;
// Initial approximation using bit manipulation
double initialSqrtEstimate(double x) {
db.value = x;
// Bit manipulation to get a rough estimate of the square root
db.bits = (db.bits & 0x800FFFFFFFFFFFFFULL) | (((db.bits & 0x7FF0000000000000ULL) >> 1) + 0x1FF0000000000000ULL);
return db.value;
}
union {
float value;
uint32_t bits;
} db3;
// Function to calculate the reciprocal using bit manipulation and Newton-Raphson method
float reciprocal(float x) {
db3.value = float(x);
// Initialize an estimate of the reciprocal of x using bit manipulation
db3.bits = 0x7eed4f50 - db3.bits;
// Refine the estimate using the Newton-Raphson method
float y = float(db3.value);
for (int i = 0; i < 2; i++) {
y = y * (2.0 - x * y); // Newton-Raphson iteration for reciprocal
}
return y;
}
// Another iterative method with dynamic initial approximation
double anothersMethod2(double number, double precision, int& iterations, bool showIteration) {
if (number == 0) return 0;
int p = int(number) >> 1;
double guess = 0;
double nextGuess = initialSqrtEstimate(number) + (number / (1 << p));
iterations = 0;
while (true) {
if (std::fabs(nextGuess - guess) < precision) {
break;
}
iterations++;
if (showIteration && showAnothersIteration) {
std::cout << "Another's method 2 - ";
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10) << nextGuess << " and more...";
if (std::fabs(nextGuess - guess) < precision) {
std::cout << " reached desired precision";
std::cout << std::endl;
break;
}
std::cout << std::endl;
}
guess = nextGuess;
nextGuess = 0.5 * (guess + number / guess);
}
return guess;
}
// Another iterative method using initial approximation and multiplication-only formula
double anothersMethod3(double number, double precision, int& iterations, bool showIteration) {
if (number == 0) return 0;
double f = initialSqrtEstimate(number); // Using the initial approximation
double prev_f = 0;
iterations = 0;
while (iterations < MAX_ITERATIONS) {
// Check if the value converges within the given precision
if (std::fabs(f - prev_f) < precision) {
break;
}
iterations++;
if (showIteration && showAnothersIteration) {
std::cout << "Another's method 3 - ";
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10) << f << " and more...";
if (std::fabs(f - prev_f) < precision) {
std::cout << " reached desired precision";
}
std::cout << std::endl;
}
prev_f = f;
f = 0.5 * (f + number * reciprocal(f)); // Use multiplication for refinement
}
// Ensure the final value meets the precision requirement
if (showIteration && std::fabs(f * f - number) > precision) {
std::cerr << "Warning: Convergence not achieved to desired precision\n";
}
return f;
}
union {
float value;
uint32_t bits;
} db2;
// Function to calculate the inverse square root using Carmack's method
float inverseSqrt(float x) {
db2.value = x;
db2.bits = 0x5f3759df - (db2.bits >> 1); // Initial approximation using magic number
return db2.value;
}
// Function to calculate the square root using the inverse square root
float carmacksMethod(float number, float precision, int& iterations, bool showIteration) {
if (number == 0) return 0;
float invSqrt = inverseSqrt(number); // Get the inverse square root
float sqrt = 1 / invSqrt; // Calculate the square root by taking the reciprocal of the inverse
iterations = 1;
if (showIteration) {
std::cout << "Carmack's method - ";
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10) << sqrt << " and more...";
std::cout << " reached desired precision";
std::cout << std::endl;
}
return sqrt;
}
// Carmack's Method with a mix of inverse square root and refinement
float carmacksMethod2(float number, float precision, int& iterations, bool showIteration) {
if (number == 0) return 0;
float invSqrt = inverseSqrt(number); // Get the inverse square root
float sqrt = 1 / invSqrt; // Calculate the square root by taking the reciprocal of the inverse
float prev_sqrt = 0;
iterations = 0;
while (true) {
if (std::fabs(sqrt - prev_sqrt) < precision) {
break;
}
iterations++;
if (showIteration) {
std::cout << "Carmack's method 2 - ";
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10) << sqrt << " and more...";
if (std::fabs(sqrt - prev_sqrt) < precision) {
std::cout << " reached desired precision";
}
std::cout << std::endl;
}
prev_sqrt = sqrt;
sqrt = 0.5 * (sqrt + number / sqrt);
}
return sqrt;
}
// Function to calculate the error
double calculateError(double root, double number) {
double square = root * root;
return std::fabs(square - number);
}
void showIterations(double number, double& resultNewton, double* resultAnothers, double& resultCarmack, double& resultCarmack2, int& iterationsNewton, int* iterationsAnothers, int& iterationsCarmack, int& iterationsCarmack2) {
resultNewton = newtonSqrt(number, precision, iterationsNewton, true);
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10)
<< "Newton's method final result: " << resultNewton << " reached desired precision, Iterations: " << iterationsNewton << "\n\n";
resultAnothers[0] = anothersMethod(number, precision, iterationsAnothers[0], true);
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10)
<< "Another's method final result: " << resultAnothers[0] << " reached desired precision, Iterations: " << iterationsAnothers[0] << "\n\n";
resultAnothers[1] = anothersMethod2(number, precision, iterationsAnothers[1], true);
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10)
<< "Another's method 2 final result: " << resultAnothers[1] << " reached desired precision, Iterations: " << iterationsAnothers[1] << "\n\n";
resultAnothers[2] = anothersMethod3(number, precision, iterationsAnothers[2], true);
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10)
<< "Another's method 3 final result: " << resultAnothers[2] << " reached desired precision, Iterations: " << iterationsAnothers[2] << "\n\n";
resultCarmack = carmacksMethod(number, precision, iterationsCarmack, true);
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10)
<< "Carmack's method final result: " << resultCarmack << " reached desired precision, Iterations: " << iterationsCarmack << "\n\n";
resultCarmack2 = carmacksMethod2(number, precision, iterationsCarmack2, true);
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10)
<< "Carmack's method 2 final result: " << resultCarmack2 << " reached desired precision, Iterations: " << iterationsCarmack2 << "\n\n";
}
void measureTime(double* randomNumbers, std::vector<double>& timesSqrt, std::vector<double>& timesNewton, std::vector<double>* timesAnothers, std::vector<double>& timesCarmack, std::vector<double>& timesCarmack2, std::vector<double>& timesDivision, std::vector<double>& timesMultiplication, std::vector<IterationData>& newtonData, std::vector<IterationData>* anothersData, std::vector<IterationData>& carmackData, std::vector<IterationData>& carmack2Data) {
// Measuring time for standard sqrt function
std::cout << "Calculating times...\n";
auto startSqrt = std::chrono::high_resolution_clock::now();
for (int i = 0; i < MAX_ITERATIONS; i++) {
volatile double result = std::sqrt(randomNumbers[i]);
}
auto endSqrt = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> durationSqrt = endSqrt - startSqrt;
timesSqrt.push_back(durationSqrt.count());
// Measuring time for Newton's pure method
auto startNewton = std::chrono::high_resolution_clock::now();
for (int i = 0; i < MAX_ITERATIONS; i++) {
int iterationsNewton = 0;
double result = newtonSqrt(randomNumbers[i], precision, iterationsNewton, false);
newtonData.push_back({ randomNumbers[i], result, iterationsNewton });
}
auto endNewton = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> durationNewton = endNewton - startNewton;
timesNewton.push_back(durationNewton.count());
// Measuring time for the another's method
auto startAnothers = std::chrono::high_resolution_clock::now();
for (int i = 0; i < MAX_ITERATIONS; i++) {
int iterationsAnothers = 0;
double result = anothersMethod(randomNumbers[i], precision, iterationsAnothers, false);
anothersData[0].push_back({ randomNumbers[i], result, iterationsAnothers });
}
auto endAnothers = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> durationAnothers = endAnothers - startAnothers;
timesAnothers[0].push_back(durationAnothers.count());
// Measuring time for the another's method 2
auto startAnothers2 = std::chrono::high_resolution_clock::now();
for (int i = 0; i < MAX_ITERATIONS; i++) {
int iterationsAnothers = 0;
double result = anothersMethod2(randomNumbers[i], precision, iterationsAnothers, false);
anothersData[1].push_back({ randomNumbers[i], result, iterationsAnothers });
}
auto endAnothers2 = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> durationAnothers2 = endAnothers2 - startAnothers2;
timesAnothers[1].push_back(durationAnothers2.count());
// Measuring time for the another's method 3
auto startAnothers3 = std::chrono::high_resolution_clock::now();
for (int i = 0; i < MAX_ITERATIONS; i++) {
int iterationsAnothers = 0;
double result = anothersMethod3(randomNumbers[i], precision, iterationsAnothers, false);
anothersData[2].push_back({ randomNumbers[i], result, iterationsAnothers });
}
auto endAnothers3 = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> durationAnothers3 = endAnothers3 - startAnothers3;
timesAnothers[2].push_back(durationAnothers3.count());
// Measuring time for Carmack's method
auto startCarmack = std::chrono::high_resolution_clock::now();
for (int i = 0; i < MAX_ITERATIONS; i++) {
int iterationsCarmack = 0;
double result = carmacksMethod(randomNumbers[i], precision, iterationsCarmack, false);
carmackData.push_back({ randomNumbers[i], result, iterationsCarmack });
}
auto endCarmack = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> durationCarmack = endCarmack - startCarmack;
timesCarmack.push_back(durationCarmack.count());
// Measuring time for Carmack's method 2
auto startCarmack2 = std::chrono::high_resolution_clock::now();
for (int i = 0; i < MAX_ITERATIONS; i++) {
int iterationsCarmack2 = 0;
double result = carmacksMethod2(randomNumbers[i], precision, iterationsCarmack2, false);
carmack2Data.push_back({ randomNumbers[i], result, iterationsCarmack2 });
}
auto endCarmack2 = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> durationCarmack2 = endCarmack2 - startCarmack2;
timesCarmack2.push_back(durationCarmack2.count());
// Measuring time for division by 2
auto startDivision = std::chrono::high_resolution_clock::now();
for (int i = 0; i < MAX_ITERATIONS; i++) {
volatile double result = 2.0 / randomNumbers[i];
}
auto endDivision = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> durationDivision = endDivision - startDivision;
timesDivision.push_back(durationDivision.count());
// Measuring time for multiplication by 2
auto startMultiplication = std::chrono::high_resolution_clock::now();
for (int i = 0; i < MAX_ITERATIONS; i++) {
volatile double result = 2.0 * randomNumbers[i];
}
auto endMultiplication = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> durationMultiplication = endMultiplication - startMultiplication;
timesMultiplication.push_back(durationMultiplication.count());
}
void displayAverageTimes(const std::vector<double>& timesSqrt, const std::vector<double>& timesNewton, const std::vector<double>* timesAnothers, const std::vector<double>& timesCarmack, const std::vector<double>& timesCarmack2, const std::vector<double>& timesDivision, const std::vector<double>& timesMultiplication) {
double avgSqrt = std::accumulate(timesSqrt.begin(), timesSqrt.end(), 0.0) / timesSqrt.size();
double avgNewton = std::accumulate(timesNewton.begin(), timesNewton.end(), 0.0) / timesNewton.size();
double avgAnothers = std::accumulate(timesAnothers[0].begin(), timesAnothers[0].end(), 0.0) / timesAnothers[0].size();
double avgAnothers2 = std::accumulate(timesAnothers[1].begin(), timesAnothers[1].end(), 0.0) / timesAnothers[1].size();
double avgAnothers3 = std::accumulate(timesAnothers[2].begin(), timesAnothers[2].end(), 0.0) / timesAnothers[2].size();
double avgCarmack = std::accumulate(timesCarmack.begin(), timesCarmack.end(), 0.0) / timesCarmack.size();
double avgCarmack2 = std::accumulate(timesCarmack2.begin(), timesCarmack2.end(), 0.0) / timesCarmack2.size();
double avgDivision = std::accumulate(timesDivision.begin(), timesDivision.end(), 0.0) / timesDivision.size();
double avgMultiplication = std::accumulate(timesMultiplication.begin(), timesMultiplication.end(), 0.0) / timesMultiplication.size();
std::cout << "\nAverage Results:\n";
std::cout << std::scientific << std::setprecision(6); // Ensure values are displayed in scientific notation
std::cout << "Standard sqrt average time (ms): " << avgSqrt << std::endl;
std::cout << "Newton's method average time (ms): " << avgNewton << std::endl;
std::cout << "Another's method average time (ms): " << avgAnothers << std::endl;
std::cout << "Another's method 2 average time (ms): " << avgAnothers2 << std::endl;
std::cout << "Another's method 3 average time (ms): " << avgAnothers3 << std::endl;
std::cout << "Carmack's method average time (ms): " << avgCarmack << std::endl;
std::cout << "Carmack's method 2 average time (ms): " << avgCarmack2 << std::endl;
std::cout << "Division by 2 average time (ms): " << avgDivision << std::endl;
std::cout << "Multiplication by 2 average time (ms): " << avgMultiplication << std::endl;
}
void calculateAndDisplayErrors(double number, const std::vector<double>& roots) {
double actualSqrt = std::sqrt(number);
std::cout << "\nError comparison with actual sqrt(" << number << "): " << std::setprecision(std::numeric_limits<double>::max_digits10) << actualSqrt << "\n";
for (size_t i = 0; i < roots.size(); ++i) {
double error = calculateError(roots[i], number);
std::cout << "Error for root " << i + 1 << " (" << std::scientific << std::setprecision(std::numeric_limits<double>::max_digits10) << roots[i] << "): " << error << "\n";
}
}
void displaySomeIterations(const std::vector<IterationData>& newtonData, const std::vector<IterationData>* anothersData, const std::vector<IterationData>& carmackData, const std::vector<IterationData>& carmack2Data) {
std::vector<IterationData> sortedNewtonData = newtonData;
std::vector<IterationData> sortedAnothersData = anothersData[0];
std::vector<IterationData> sortedAnothersData1 = anothersData[1];
std::vector<IterationData> sortedAnothersData2 = anothersData[2];
std::vector<IterationData> sortedCarmackData = carmackData;
std::vector<IterationData> sortedCarmack2Data = carmack2Data;
// Sort the data based on the number of iterations
std::sort(sortedNewtonData.begin(), sortedNewtonData.end(), [](const IterationData& a, const IterationData& b) {
return a.iterations > b.iterations;
});
std::sort(sortedAnothersData.begin(), sortedAnothersData.end(), [](const IterationData& a, const IterationData& b) {
return a.iterations > b.iterations;
});
std::sort(sortedAnothersData1.begin(), sortedAnothersData1.end(), [](const IterationData& a, const IterationData& b) {
return a.iterations > b.iterations;
});
std::sort(sortedAnothersData2.begin(), sortedAnothersData2.end(), [](const IterationData& a, const IterationData& b) {
return a.iterations > b.iterations;
});
std::sort(sortedCarmackData.begin(), sortedCarmackData.end(), [](const IterationData& a, const IterationData& b) {
return a.iterations > b.iterations;
});
std::sort(sortedCarmack2Data.begin(), sortedCarmack2Data.end(), [](const IterationData& a, const IterationData& b) {
return a.iterations > b.iterations;
});
std::cout << "\nSome random numbers and their iterations for Newton's method:\n";
for (size_t i = 0; i < 10 && i < sortedNewtonData.size(); ++i) {
std::cout << "Number: " << sortedNewtonData[i].number
<< ", Iterations: " << sortedNewtonData[i].iterations
<< ", Sqrt: " << sortedNewtonData[i].sqrtResult << "\n";
}
std::cout << "\nSome random numbers and their iterations for Another's method:\n";
for (size_t i = 0; i < 10 && i < sortedAnothersData.size(); ++i) {
std::cout << "Number: " << sortedAnothersData[0, i].number
<< ", Iterations: " << sortedAnothersData[0, i].iterations
<< ", Sqrt: " << sortedAnothersData[0, i].sqrtResult << "\n";
}
std::cout << "\nSome random numbers and their iterations for Another's method 2:\n";
for (size_t i = 0; i < 10 && i < sortedAnothersData.size(); ++i) {
std::cout << "Number: " << sortedAnothersData[1, i].number
<< ", Iterations: " << sortedAnothersData[1, i].iterations
<< ", Sqrt: " << sortedAnothersData[1, i].sqrtResult << "\n";
}
std::cout << "\nSome random numbers and their iterations for Another's method 3:\n";
for (size_t i = 0; i < 10 && i < sortedAnothersData.size(); ++i) {
std::cout << "Number: " << sortedAnothersData[2, i].number
<< ", Iterations: " << sortedAnothersData[2, i].iterations
<< ", Sqrt: " << sortedAnothersData[2, i].sqrtResult << "\n";
}
std::cout << "\nSome random numbers and their iterations for Carmack's method:\n";
for (size_t i = 0; i < 10 && i < sortedCarmackData.size(); ++i) {
std::cout << "Number: " << sortedCarmackData[i].number
<< ", Iterations: " << sortedCarmackData[i].iterations
<< ", Sqrt: " << sortedCarmackData[i].sqrtResult << "\n";
}
std::cout << "\nSome random numbers and their iterations for Carmack's method 2:\n";
for (size_t i = 0; i < 10 && i < sortedCarmack2Data.size(); ++i) {
std::cout << "Number: " << sortedCarmack2Data[i].number
<< ", Iterations: " << sortedCarmack2Data[i].iterations
<< ", Sqrt: " << sortedCarmack2Data[i].sqrtResult << "\n";
}
}
void clearScreen() {
#ifdef _WIN32
system("cls");
#else
system("clear");
#endif
}
int main() {
double number;
std::cout << "Enter the number to find the square root: ";
std::cin >> number;
// Show iterations for each method with user input
double resultNewton, resultAnothers[3], resultCarmack, resultCarmack2;
int iterationsNewton, iterationsAnothers[3], iterationsCarmack, iterationsCarmack2;
showIterations(number, resultNewton, resultAnothers, resultCarmack, resultCarmack2, iterationsNewton, iterationsAnothers, iterationsCarmack, iterationsCarmack2);
std::cout << "Press enter to continue . . .";
std::cin.get();
std::cin.get();
std::vector<double> timesSqrt, timesNewton, timesAnothers[3], timesCarmack, timesCarmack2, timesDivision, timesMultiplication;
std::vector<IterationData> newtonData, anothersData[3], carmackData, carmack2Data;
double* randomNumbers = new double[MAX_ITERATIONS];
std::mt19937_64 rng;
std::uniform_real_distribution<double> dist(1.0, 100.0); // Random numbers between 1 and 100
for (int i = 0; i < MAX_ITERATIONS; i++) {
randomNumbers[i] = dist(rng);
}
measureTime(randomNumbers, timesSqrt, timesNewton, timesAnothers, timesCarmack, timesCarmack2, timesDivision, timesMultiplication, newtonData, anothersData, carmackData, carmack2Data);
delete[] randomNumbers;
std::cout << "Press enter to continue to error calculations . . .";
std::cin.get();
// Display the error calculations
std::vector<double> roots = { resultNewton, resultAnothers[0], resultAnothers[1], resultAnothers[2], resultCarmack, resultCarmack2 };
calculateAndDisplayErrors(number, roots);
std::cout << "Press enter to continue to time measurements . . .";
std::cin.get();
// Display the average times
displayAverageTimes(timesSqrt, timesNewton, timesAnothers, timesCarmack, timesCarmack2, timesDivision, timesMultiplication);
std::cout << "Press enter to continue to top iterations display . . .";
std::cin.get();
// Display the top iterations
std::cout << "Some random numbers and their iterations:\n";
displaySomeIterations(newtonData, anothersData, carmackData, carmack2Data);
std::cout << "Press enter to exit . . .";
std::cin.get();
return 0;
}
I came from Pascal, and following the recommendations of user Rish, this wasn't working; I don't know what I was thinking. I think in Pascal it could work this way, but I don't remember. In other words, that double indexing in the another's variables... Another thing I did was to name the most likely discoverers, as advised by Adam Hyland.
#include <iomanip>
#include <cmath>
#include <chrono>
#include <limits>
#include <vector>
#include <random>
#include <algorithm>
#include <numeric>
#include <iostream>
// Constants
const int MAX_ITERATIONS = 1000000;
const double precision = 1e-3; // Adjusted precision
bool showNewtonIteration = true;
bool showAnothersIteration = true;
struct IterationData {
double number;
double sqrtResult;
int iterations;
};
// Optimized Newton's method for finding the square root
double newtonSqrt(double number, double precision, int& iterations, bool showIteration) {
if (number == 0) return 0;
double guess = number * 0.5; // Starting guess
double nextGuess = 0;
iterations = 0;
while (true) {
if (std::fabs(guess - nextGuess) < precision) {
break;
}
iterations++;
if (showIteration && showNewtonIteration) {
std::cout << "Newton's method - ";
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10) << guess << " and more...";
if (std::fabs(guess - nextGuess) < precision) {
std::cout << " reached desired precision";
}
std::cout << std::endl;
}
nextGuess = guess;
guess = 0.5 * (guess + number / guess);
}
return nextGuess;
}
// Iterative another's method with dynamic initial approximation
double anothersMethod(double number, double precision, int& iterations, bool showIteration) {
double f = number * 0.5; // Using the initial approximation
double prev_f = 0;
iterations = 0;
while (true) {
// Check if the value converges within the given precision
if (std::fabs(f - prev_f) < precision) {
break;
}
iterations++;
if (showIteration && showAnothersIteration) {
std::cout << "Another's method - ";
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10) << f << " and more...";
if (std::fabs(f - prev_f) < precision) {
std::cout << " reached desired precision";
}
std::cout << std::endl;
}
prev_f = f;
// New formula to improve the estimate
f = f - (f * f - number) / (f + number / f);
}
return f;
}
// Union to manipulate double as an integer (bit manipulation)
union {
double value;
uint64_t bits;
} db;
// Initial approximation using bit manipulation
double initialSqrtEstimate(double x) {
db.value = x;
// Bit manipulation to get a rough estimate of the square root
db.bits = (db.bits & 0x800FFFFFFFFFFFFFULL) | (((db.bits & 0x7FF0000000000000ULL) >> 1) + 0x1FF0000000000000ULL);
return db.value;
}
union {
float value;
uint32_t bits;
} db3;
// Function to calculate the reciprocal using bit manipulation and Newton-Raphson method
float reciprocal(float x) {
db3.value = float(x);
// Initialize an estimate of the reciprocal of x using bit manipulation
db3.bits = 0x7eed4f50 - db3.bits;
// Refine the estimate using the Newton-Raphson method
float y = float(db3.value);
for (int i = 0; i < 2; i++) {
y = y * (2.0 - x * y); // Newton-Raphson iteration for reciprocal
}
return y;
}
// Another iterative method with dynamic initial approximation
double anothersMethod2(double number, double precision, int& iterations, bool showIteration) {
if (number == 0) return 0;
int p = int(number) >> 1;
double guess = 0;
double nextGuess = initialSqrtEstimate(number) + (number / (1 << p));
iterations = 0;
while (true) {
if (std::fabs(nextGuess - guess) < precision) {
break;
}
iterations++;
if (showIteration && showAnothersIteration) {
std::cout << "Another's method 2 - ";
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10) << nextGuess << " and more...";
if (std::fabs(nextGuess - guess) < precision) {
std::cout << " reached desired precision";
std::cout << std::endl;
break;
}
std::cout << std::endl;
}
guess = nextGuess;
nextGuess = 0.5 * (guess + number / guess);
}
return guess;
}
// Another iterative method using initial approximation and multiplication-only formula
double anothersMethod3(double number, double precision, int& iterations, bool showIteration) {
if (number == 0) return 0;
double f = initialSqrtEstimate(number); // Using the initial approximation
double prev_f = 0;
iterations = 0;
while (iterations < MAX_ITERATIONS) {
// Check if the value converges within the given precision
if (std::fabs(f - prev_f) < precision) {
break;
}
iterations++;
if (showIteration && showAnothersIteration) {
std::cout << "Another's method 3 - ";
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10) << f << " and more...";
if (std::fabs(f - prev_f) < precision) {
std::cout << " reached desired precision";
}
std::cout << std::endl;
}
prev_f = f;
f = 0.5 * (f + number * reciprocal(f)); // Use multiplication for refinement
}
// Ensure the final value meets the precision requirement
if (showIteration && std::fabs(f * f - number) > precision) {
std::cerr << "Warning: Convergence not achieved to desired precision\n";
}
return f;
}
union {
float value;
uint32_t bits;
} db2;
// Function to calculate the inverse square root using Moler-Walsh method
float inverseSqrt(float x) {
db2.value = x;
db2.bits = 0x5f3759df - (db2.bits >> 1); // Initial approximation using magic number
return db2.value;
}
// Function to calculate the square root using the inverse square root
float molerwalshMethod(float number, float precision, int& iterations, bool showIteration) {
if (number == 0) return 0;
float invSqrt = inverseSqrt(number); // Get the inverse square root
float sqrt = 1 / invSqrt; // Calculate the square root by taking the reciprocal of the inverse
iterations = 1;
if (showIteration) {
std::cout << "Moler-Walsh method - ";
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10) << sqrt << " and more...";
std::cout << " reached desired precision";
std::cout << std::endl;
}
return sqrt;
}
// Moler-Walsh Method with a mix of inverse square root and refinement
float molerwalshMethod2(float number, float precision, int& iterations, bool showIteration) {
if (number == 0) return 0;
float invSqrt = inverseSqrt(number); // Get the inverse square root
float sqrt = 1 / invSqrt; // Calculate the square root by taking the reciprocal of the inverse
float prev_sqrt = 0;
iterations = 0;
while (true) {
if (std::fabs(sqrt - prev_sqrt) < precision) {
break;
}
iterations++;
if (showIteration) {
std::cout << "Moler-Walsh method 2 - ";
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10) << sqrt << " and more...";
if (std::fabs(sqrt - prev_sqrt) < precision) {
std::cout << " reached desired precision";
}
std::cout << std::endl;
}
prev_sqrt = sqrt;
sqrt = 0.5 * (sqrt + number / sqrt);
}
return sqrt;
}
// Function to calculate the error
double calculateError(double root, double number) {
double square = root * root;
return std::fabs(square - number);
}
void showIterations(double number, double& resultNewton, double* resultAnothers, double& resultCarmack, double& resultCarmack2, int& iterationsNewton, int* iterationsAnothers, int& iterationsCarmack, int& iterationsCarmack2) {
resultNewton = newtonSqrt(number, precision, iterationsNewton, true);
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10)
<< "Newton's method final result: " << resultNewton << " reached desired precision, Iterations: " << iterationsNewton << "\n\n";
resultAnothers[0] = anothersMethod(number, precision, iterationsAnothers[0], true);
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10)
<< "Another's method final result: " << resultAnothers[0] << " reached desired precision, Iterations: " << iterationsAnothers[0] << "\n\n";
resultAnothers[1] = anothersMethod2(number, precision, iterationsAnothers[1], true);
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10)
<< "Another's method 2 final result: " << resultAnothers[1] << " reached desired precision, Iterations: " << iterationsAnothers[1] << "\n\n";
resultAnothers[2] = anothersMethod3(number, precision, iterationsAnothers[2], true);
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10)
<< "Another's method 3 final result: " << resultAnothers[2] << " reached desired precision, Iterations: " << iterationsAnothers[2] << "\n\n";
resultCarmack = molerwalshMethod(number, precision, iterationsCarmack, true);
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10)
<< "Moler-Walsh method final result: " << resultCarmack << " reached desired precision, Iterations: " << iterationsCarmack << "\n\n";
resultCarmack2 = molerwalshMethod2(number, precision, iterationsCarmack2, true);
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10)
<< "Moler-Walsh method 2 final result: " << resultCarmack2 << " reached desired precision, Iterations: " << iterationsCarmack2 << "\n\n";
}
void measureTime(double* randomNumbers, std::vector<double>& timesSqrt, std::vector<double>& timesNewton, std::vector<double>* timesAnothers, std::vector<double>& timesCarmack, std::vector<double>& timesCarmack2, std::vector<double>& timesDivision, std::vector<double>& timesMultiplication, std::vector<IterationData>& newtonData, std::vector<IterationData>* anothersData, std::vector<IterationData>& carmackData, std::vector<IterationData>& carmack2Data) {
// Measuring time for standard sqrt function
std::cout << "Calculating times...\n";
auto startSqrt = std::chrono::high_resolution_clock::now();
for (int i = 0; i < MAX_ITERATIONS; i++) {
volatile double result = std::sqrt(randomNumbers[i]);
}
auto endSqrt = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> durationSqrt = endSqrt - startSqrt;
timesSqrt.push_back(durationSqrt.count());
// Measuring time for Newton's pure method
auto startNewton = std::chrono::high_resolution_clock::now();
for (int i = 0; i < MAX_ITERATIONS; i++) {
int iterationsNewton = 0;
double result = newtonSqrt(randomNumbers[i], precision, iterationsNewton, false);
newtonData.push_back({ randomNumbers[i], result, iterationsNewton });
}
auto endNewton = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> durationNewton = endNewton - startNewton;
timesNewton.push_back(durationNewton.count());
// Measuring time for the another's method
auto startAnothers = std::chrono::high_resolution_clock::now();
for (int i = 0; i < MAX_ITERATIONS; i++) {
int iterationsAnothers = 0;
double result = anothersMethod(randomNumbers[i], precision, iterationsAnothers, false);
anothersData[0].push_back({ randomNumbers[i], result, iterationsAnothers });
}
auto endAnothers = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> durationAnothers = endAnothers - startAnothers;
timesAnothers[0].push_back(durationAnothers.count());
// Measuring time for the another's method 2
auto startAnothers2 = std::chrono::high_resolution_clock::now();
for (int i = 0; i < MAX_ITERATIONS; i++) {
int iterationsAnothers = 0;
double result = anothersMethod2(randomNumbers[i], precision, iterationsAnothers, false);
anothersData[1].push_back({ randomNumbers[i], result, iterationsAnothers });
}
auto endAnothers2 = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> durationAnothers2 = endAnothers2 - startAnothers2;
timesAnothers[1].push_back(durationAnothers2.count());
// Measuring time for the another's method 3
auto startAnothers3 = std::chrono::high_resolution_clock::now();
for (int i = 0; i < MAX_ITERATIONS; i++) {
int iterationsAnothers = 0;
double result = anothersMethod3(randomNumbers[i], precision, iterationsAnothers, false);
anothersData[2].push_back({ randomNumbers[i], result, iterationsAnothers });
}
auto endAnothers3 = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> durationAnothers3 = endAnothers3 - startAnothers3;
timesAnothers[2].push_back(durationAnothers3.count());
// Measuring time for Moler-Walsh method
auto startCarmack = std::chrono::high_resolution_clock::now();
for (int i = 0; i < MAX_ITERATIONS; i++) {
int iterationsCarmack = 0;
double result = molerwalshMethod(randomNumbers[i], precision, iterationsCarmack, false);
carmackData.push_back({ randomNumbers[i], result, iterationsCarmack });
}
auto endCarmack = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> durationCarmack = endCarmack - startCarmack;
timesCarmack.push_back(durationCarmack.count());
// Measuring time for Moler-Walsh method 2
auto startCarmack2 = std::chrono::high_resolution_clock::now();
for (int i = 0; i < MAX_ITERATIONS; i++) {
int iterationsCarmack2 = 0;
double result = molerwalshMethod2(randomNumbers[i], precision, iterationsCarmack2, false);
carmack2Data.push_back({ randomNumbers[i], result, iterationsCarmack2 });
}
auto endCarmack2 = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> durationCarmack2 = endCarmack2 - startCarmack2;
timesCarmack2.push_back(durationCarmack2.count());
// Measuring time for division by 2
auto startDivision = std::chrono::high_resolution_clock::now();
for (int i = 0; i < MAX_ITERATIONS; i++) {
volatile double result = 2.0 / randomNumbers[i];
}
auto endDivision = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> durationDivision = endDivision - startDivision;
timesDivision.push_back(durationDivision.count());
// Measuring time for multiplication by 2
auto startMultiplication = std::chrono::high_resolution_clock::now();
for (int i = 0; i < MAX_ITERATIONS; i++) {
volatile double result = 2.0 * randomNumbers[i];
}
auto endMultiplication = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> durationMultiplication = endMultiplication - startMultiplication;
timesMultiplication.push_back(durationMultiplication.count());
}
void displayAverageTimes(const std::vector<double>& timesSqrt, const std::vector<double>& timesNewton, const std::vector<double>* timesAnothers, const std::vector<double>& timesCarmack, const std::vector<double>& timesCarmack2, const std::vector<double>& timesDivision, const std::vector<double>& timesMultiplication) {
double avgSqrt = std::accumulate(timesSqrt.begin(), timesSqrt.end(), 0.0) / timesSqrt.size();
double avgNewton = std::accumulate(timesNewton.begin(), timesNewton.end(), 0.0) / timesNewton.size();
double avgAnothers = std::accumulate(timesAnothers[0].begin(), timesAnothers[0].end(), 0.0) / timesAnothers[0].size();
double avgAnothers2 = std::accumulate(timesAnothers[1].begin(), timesAnothers[1].end(), 0.0) / timesAnothers[1].size();
double avgAnothers3 = std::accumulate(timesAnothers[2].begin(), timesAnothers[2].end(), 0.0) / timesAnothers[2].size();
double avgCarmack = std::accumulate(timesCarmack.begin(), timesCarmack.end(), 0.0) / timesCarmack.size();
double avgCarmack2 = std::accumulate(timesCarmack2.begin(), timesCarmack2.end(), 0.0) / timesCarmack2.size();
double avgDivision = std::accumulate(timesDivision.begin(), timesDivision.end(), 0.0) / timesDivision.size();
double avgMultiplication = std::accumulate(timesMultiplication.begin(), timesMultiplication.end(), 0.0) / timesMultiplication.size();
std::cout << "\nAverage Results:\n";
std::cout << std::scientific << std::setprecision(6); // Ensure values are displayed in scientific notation
std::cout << "Standard sqrt average time (ms): " << avgSqrt << std::endl;
std::cout << "Newton's method average time (ms): " << avgNewton << std::endl;
std::cout << "Another's method average time (ms): " << avgAnothers << std::endl;
std::cout << "Another's method 2 average time (ms): " << avgAnothers2 << std::endl;
std::cout << "Another's method 3 average time (ms): " << avgAnothers3 << std::endl;
std::cout << "Moler-Walsh method average time (ms): " << avgCarmack << std::endl;
std::cout << "Moler-Walsh method 2 average time (ms): " << avgCarmack2 << std::endl;
std::cout << "Division by 2 average time (ms): " << avgDivision << std::endl;
std::cout << "Multiplication by 2 average time (ms): " << avgMultiplication << std::endl;
}
void calculateAndDisplayErrors(double number, const std::vector<double>& roots) {
double actualSqrt = std::sqrt(number);
std::cout << "\nError comparison with actual sqrt(" << number << "): " << std::setprecision(std::numeric_limits<double>::max_digits10) << actualSqrt << "\n";
for (size_t i = 0; i < roots.size(); ++i) {
double error = calculateError(roots[i], number);
std::cout << "Error for root " << i + 1 << " (" << std::scientific << std::setprecision(std::numeric_limits<double>::max_digits10) << roots[i] << "): " << error << "\n";
}
}
void displaySomeIterations(const std::vector<IterationData>& newtonData, const std::vector<IterationData>& anothersData1, const std::vector<IterationData>& anothersData2, const std::vector<IterationData>& anothersData3, const std::vector<IterationData>& carmackData, const std::vector<IterationData>& carmack2Data) {
std::vector<IterationData> sortedNewtonData = newtonData;
std::vector<IterationData> sortedAnothersData1 = anothersData1;
std::vector<IterationData> sortedAnothersData2 = anothersData2;
std::vector<IterationData> sortedAnothersData3 = anothersData3;
std::vector<IterationData> sortedCarmackData = carmackData;
std::vector<IterationData> sortedCarmack2Data = carmack2Data;
// Sort the data based on the number of iterations
std::sort(sortedNewtonData.begin(), sortedNewtonData.end(), [](const IterationData& a, const IterationData& b) {
return a.iterations > b.iterations;
});
std::sort(sortedAnothersData1.begin(), sortedAnothersData1.end(), [](const IterationData& a, const IterationData& b) {
return a.iterations > b.iterations;
});
std::sort(sortedAnothersData2.begin(), sortedAnothersData2.end(), [](const IterationData& a, const IterationData& b) {
return a.iterations > b.iterations;
});
std::sort(sortedAnothersData3.begin(), sortedAnothersData3.end(), [](const IterationData& a, const IterationData& b) {
return a.iterations > b.iterations;
});
std::sort(sortedCarmackData.begin(), sortedCarmackData.end(), [](const IterationData& a, const IterationData& b) {
return a.iterations > b.iterations;
});
std::sort(sortedCarmack2Data.begin(), sortedCarmack2Data.end(), [](const IterationData& a, const IterationData& b) {
return a.iterations > b.iterations;
});
std::cout << "\nSome random numbers and their iterations for Newton's method:\n";
for (size_t i = 0; i < 10 && i < sortedNewtonData.size(); ++i) {
std::cout << "Number: " << sortedNewtonData[i].number
<< ", Iterations: " << sortedNewtonData[i].iterations
<< ", Sqrt: " << sortedNewtonData[i].sqrtResult << "\n";
}
std::cout << "\nSome random numbers and their iterations for Another's method:\n";
for (size_t i = 0; i < 10 && i < sortedAnothersData1.size(); ++i) {
std::cout << "Number: " << sortedAnothersData1[i].number
<< ", Iterations: " << sortedAnothersData1[i].iterations
<< ", Sqrt: " << sortedAnothersData1[i].sqrtResult << "\n";
}
std::cout << "\nSome random numbers and their iterations for Another's method 2:\n";
for (size_t i = 0; i < 10 && i < sortedAnothersData2.size(); ++i) {
std::cout << "Number: " << sortedAnothersData2[i].number
<< ", Iterations: " << sortedAnothersData2[i].iterations
<< ", Sqrt: " << sortedAnothersData2[i].sqrtResult << "\n";
}
std::cout << "\nSome random numbers and their iterations for Another's method 3:\n";
for (size_t i = 0; i < 10 && i < sortedAnothersData3.size(); ++i) {
std::cout << "Number: " << sortedAnothersData3[i].number
<< ", Iterations: " << sortedAnothersData3[i].iterations
<< ", Sqrt: " << sortedAnothersData3[i].sqrtResult << "\n";
}
std::cout << "\nSome random numbers and their iterations for Moler-Walsh method:\n";
for (size_t i = 0; i < 10 && i < sortedCarmackData.size(); ++i) {
std::cout << "Number: " << sortedCarmackData[i].number
<< ", Iterations: " << sortedCarmackData[i].iterations
<< ", Sqrt: " << sortedCarmackData[i].sqrtResult << "\n";
}
std::cout << "\nSome random numbers and their iterations for Moler-Walsh method 2:\n";
for (size_t i = 0; i < 10 && i < sortedCarmack2Data.size(); ++i) {
std::cout << "Number: " << sortedCarmack2Data[i].number
<< ", Iterations: " << sortedCarmack2Data[i].iterations
<< ", Sqrt: " << sortedCarmack2Data[i].sqrtResult << "\n";
}
}
void clearScreen() {
#ifdef _WIN32
system("cls");
#else
system("clear");
#endif
}
int main() {
double number;
std::cout << "Enter the number to find the square root: ";
std::cin >> number;
// Show iterations for each method with user input
double resultNewton, resultAnothers[3], resultCarmack, resultCarmack2;
int iterationsNewton, iterationsAnothers[3], iterationsCarmack, iterationsCarmack2;
showIterations(number, resultNewton, resultAnothers, resultCarmack, resultCarmack2, iterationsNewton, iterationsAnothers, iterationsCarmack, iterationsCarmack2);
std::cout << "Press enter to continue . . .";
std::cin.get();
std::cin.get();
std::vector<double> timesSqrt, timesNewton, timesAnothers[3], timesCarmack, timesCarmack2, timesDivision, timesMultiplication;
std::vector<IterationData> newtonData, anothersData[3], carmackData, carmack2Data;
double* randomNumbers = new double[MAX_ITERATIONS];
std::mt19937_64 rng;
std::uniform_real_distribution<double> dist(1.0, 100.0); // Random numbers between 1 and 100
for (int i = 0; i < MAX_ITERATIONS; i++) {
randomNumbers[i] = dist(rng);
}
measureTime(randomNumbers, timesSqrt, timesNewton, timesAnothers, timesCarmack, timesCarmack2, timesDivision, timesMultiplication, newtonData, { anothersData }, carmackData, carmack2Data);
delete[] randomNumbers;
std::cout << "Press enter to continue to error calculations . . .";
std::cin.get();
// Display the error calculations
std::vector<double> roots = { resultNewton, resultAnothers[0], resultAnothers[1], resultAnothers[2], resultCarmack, resultCarmack2 };
calculateAndDisplayErrors(number, roots);
std::cout << "Press enter to continue to time measurements . . .";
std::cin.get();
// Display the average times
displayAverageTimes(timesSqrt, timesNewton, timesAnothers, timesCarmack, timesCarmack2, timesDivision, timesMultiplication);
std::cout << "Press enter to continue to top iterations display . . .";
std::cin.get();
// Display the top iterations
std::cout << "Some random numbers and their iterations:\n";
displaySomeIterations(newtonData, anothersData[0], anothersData[1], anothersData[2], carmackData, carmack2Data);
std::cout << "Press enter to exit . . .";
std::cin.get();
return 0;
}
Using bit manipulation and basic algebra, I developed a faster method to find the magic number, including for direct square root calculation:
#include <iostream>
#include <vector>
#include <cmath>
#include <cstdint>
const int NUM_TESTS = 9;
union FloatInt {
float value;
uint32_t bits;
};
union DoubleInt {
double value;
uint64_t bits;
};
// Function to calculate the inverse square root
float inverseSqrt(float x) {
FloatInt num;
num.value = x;
num.bits = 0x5f3759df - (num.bits >> 1);
float y = num.value;
//y = y * (1.5f - (x * 0.5f * y * y)); // Newton-Raphson method
return y;
}
// Function to calculate the magic number
uint32_t calculateMagicNumber(const std::vector<float>& numbers, bool inverse) {
std::vector<uint32_t> bitManipulations(NUM_TESTS);
double sum = 0;
// Calculate bitManipulations from known (inverse) square roots
for (size_t i = 0; i < NUM_TESTS; ++i) {
FloatInt fi;
float rootValue;
if (inverse) {
rootValue = 1.0f / sqrt(numbers[i]);
}
else {
rootValue = sqrt(numbers[i]);
}
fi.value = rootValue;
bitManipulations[i] = fi.bits;
}
DoubleInt doubleSum;
doubleSum.value = 0.0;
// Calculate the magic number from bitManipulations
for (size_t i = 0; i < NUM_TESTS; ++i) {
FloatInt fi;
fi.value = numbers[i];
if (inverse) {
fi.value = static_cast<float>(bitManipulations[i] + (fi.bits >> 1));
}
else {
fi.value = static_cast<float>(bitManipulations[i] - (fi.bits >> 1));
}
doubleSum.value += fi.value;
}
// Calculate the average
uint32_t averageMagic = static_cast<uint32_t>(doubleSum.value / NUM_TESTS);
return averageMagic;
}
int main() {
float number;
std::cout << "Enter the number to find the square root: ";
std::cin >> number;
// Vector of known numbers
std::vector<float> knownNumbers = { 0.5f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 10.0f, 100.0f, 1000.0f };
// Calculate the approximate magic number for inverse square root
uint32_t magic = calculateMagicNumber(knownNumbers, true);
// Display the calculated magic number for inverse square root
std::cout << "Calculated magic number for inverse square root: 0x" << std::hex << magic << std::endl;
// Test the inverse square root function with the calculated magic number
FloatInt testNum;
testNum.value = number;
testNum.bits = magic - (testNum.bits >> 1);
// Calculate the approximate magic number for direct square root
uint32_t magic2 = calculateMagicNumber(knownNumbers, false);
// Display the calculated magic number for direct square root
std::cout << "Calculated magic number for direct square root: 0x" << std::hex << magic2 << std::endl;
// Test the square root function with the calculated magic number
FloatInt testNum2;
testNum2.value = number;
testNum2.bits = magic2 + (testNum2.bits >> 1);
// Test the original inverse square root function
float testNum3 = inverseSqrt(number);
std::cout << "Square root of " << number << " with calculated inverse magic number is approximately: " << std::dec << 1 / testNum.value << std::endl;
std::cout << "Square root of " << number << " with calculated magic number is approximately: " << std::dec << testNum2.value << std::endl;
std::cout << "Square root of " << number << " with original (0x5f3759df) magic number is approximately: " << std::dec << 1 / testNum3 << std::endl;
std::cout << "Square root of " << number << " with standard sqrt() is approximately: " << std::dec << sqrt(number) << std::endl;
return 0;
}
I believe it was discovered using a similar method, where, given many different inputs, the result was a similar magic number.