first commit
This commit is contained in:
175
src/ComputeOptimalShapeXYZ.cpp
Normal file
175
src/ComputeOptimalShapeXYZ.cpp
Normal file
@@ -0,0 +1,175 @@
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
|
||||
#ifdef HPCG_CUBIC_RADICAL_SEARCH
|
||||
#include <algorithm>
|
||||
#endif
|
||||
#include <map>
|
||||
|
||||
#include "ComputeOptimalShapeXYZ.hpp"
|
||||
#include "MixedBaseCounter.hpp"
|
||||
|
||||
#ifdef HPCG_CUBIC_RADICAL_SEARCH
|
||||
static int min3(int a, int b, int c)
|
||||
{
|
||||
return std::min(a, std::min(b, c));
|
||||
}
|
||||
|
||||
static int max3(int a, int b, int c)
|
||||
{
|
||||
return std::max(a, std::max(b, c));
|
||||
}
|
||||
|
||||
static void cubic_radical_search(int n, int& x, int& y, int& z)
|
||||
{
|
||||
double best = 0.0;
|
||||
|
||||
for (int f1 = (int) (pow(n, 1.0 / 3.0) + 0.5); f1 > 0; --f1)
|
||||
if (n % f1 == 0)
|
||||
{
|
||||
int n1 = n / f1;
|
||||
for (int f2 = (int) (pow(n1, 0.5) + 0.5); f2 > 0; --f2)
|
||||
if (n1 % f2 == 0)
|
||||
{
|
||||
int f3 = n1 / f2;
|
||||
double current = (double) min3(f1, f2, f3) / max3(f1, f2, f3);
|
||||
if (current > best)
|
||||
{
|
||||
best = current;
|
||||
x = f1;
|
||||
y = f2;
|
||||
z = f3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void ComputePrimeFactors(int n, std::map<int, int>& factors)
|
||||
{
|
||||
int d, sq = int((sqrt(double(n))) + 1L);
|
||||
div_t r;
|
||||
|
||||
// remove 2 as a factor with shifts instead "/" and "%"
|
||||
for (; n > 1 && (n & 1) == 0; n >>= 1)
|
||||
{
|
||||
factors[2]++;
|
||||
}
|
||||
|
||||
// keep removing subsequent odd numbers
|
||||
for (d = 3; d <= sq; d += 2)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
r = div(n, d);
|
||||
if (r.rem == 0)
|
||||
{
|
||||
factors[d]++;
|
||||
n = r.quot;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (n > 1 || factors.size() == 0) // left with a prime or x==1
|
||||
factors[n]++;
|
||||
}
|
||||
|
||||
static int pow_i(int x, int p)
|
||||
{
|
||||
int v;
|
||||
|
||||
if (0 == x || 1 == x)
|
||||
return x;
|
||||
|
||||
if (p < 0)
|
||||
return 0;
|
||||
|
||||
for (v = 1; p; p >>= 1)
|
||||
{
|
||||
if (1 & p)
|
||||
v *= x;
|
||||
x *= x;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void ComputeOptimalShapeXYZ(int xyz, int& x, int& y, int& z)
|
||||
{
|
||||
#ifdef HPCG_CUBIC_RADICAL_SEARCH
|
||||
cubic_radical_search(xyz, x, y, z);
|
||||
#else
|
||||
std::map<int, int> factors;
|
||||
|
||||
ComputePrimeFactors(xyz, factors); // factors are sorted: ascending order
|
||||
|
||||
std::map<int, int>::iterator iter = factors.begin();
|
||||
|
||||
// there is at least one prime factor
|
||||
x = (iter++)->first; // cache the first factor, move to the next one
|
||||
|
||||
y = iter != factors.end() ? (iter++)->first : y; // try to cache the second factor in "y"
|
||||
|
||||
if (factors.size() == 1)
|
||||
{ // only a single factor
|
||||
z = pow_i(x, factors[x] / 3);
|
||||
y = pow_i(x, factors[x] / 3 + ((factors[x] % 3) >= 2 ? 1 : 0));
|
||||
x = pow_i(x, factors[x] / 3 + ((factors[x] % 3) >= 1 ? 1 : 0));
|
||||
}
|
||||
else if (factors.size() == 2 && factors[x] == 1 && factors[y] == 1)
|
||||
{ // two distinct prime factors
|
||||
z = 1;
|
||||
}
|
||||
else if (factors.size() == 2 && factors[x] + factors[y] == 3)
|
||||
{ // three prime factors, one repeated
|
||||
z = factors[x] == 2 ? x : y; // test which factor is repeated
|
||||
}
|
||||
else if (factors.size() == 3 && factors[x] == 1 && factors[y] == 1 && iter->second == 1)
|
||||
{ // three distinct and single prime factors
|
||||
z = iter->first;
|
||||
}
|
||||
else
|
||||
{ // 3 or more prime factors so try all possible 3-subsets
|
||||
|
||||
int i, distinct_factors[32 + 1], count_factors[32 + 1];
|
||||
|
||||
i = 0;
|
||||
for (std::map<int, int>::iterator iter = factors.begin(); iter != factors.end(); ++iter, ++i)
|
||||
{
|
||||
distinct_factors[i] = iter->first;
|
||||
count_factors[i] = iter->second;
|
||||
}
|
||||
|
||||
// count total number of prime factors in "c_main" and distribute some factors into "c1"
|
||||
MixedBaseCounter c_main(count_factors, factors.size()), c1(count_factors, factors.size());
|
||||
|
||||
// at the beginning, minimum area is the maximum area
|
||||
double area, min_area = 2.0 * xyz + 1.0;
|
||||
|
||||
for (c1.next(); !c1.is_zero(); c1.next())
|
||||
{
|
||||
MixedBaseCounter c2(c_main, c1); // "c2" gets the factors remaining in "c_main" that "c1" doesn't have
|
||||
for (c2.next(); !c2.is_zero(); c2.next())
|
||||
{
|
||||
int tf1 = c1.product(distinct_factors);
|
||||
int tf2 = c2.product(distinct_factors);
|
||||
int tf3 = xyz / tf1 / tf2; // we derive the third dimension, we don't keep track of the factors it has
|
||||
|
||||
area = tf1 * double(tf2) + tf2 * double(tf3) + tf1 * double(tf3);
|
||||
if (area < min_area)
|
||||
{
|
||||
min_area = area;
|
||||
x = tf1;
|
||||
y = tf2;
|
||||
z = tf3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
Reference in New Issue
Block a user