好的,我的问题属于数学性质。 我有一个长度为X的字节数组,我需要找到两个最接近的数字,它们相乘在一起等于X. 我需要这样做,因为我正在从一个字节数组中构建一个位图,我需要尽可能使位图看起来像一个正方形。 我在C#中对此进行编码,但不要担心语法,任何算法或伪代码都可以。 在此先感谢您的帮助
答案 0 :(得分:10)
对于这个问题,可能有一个更好的算法,但最重要的是:
1) Take the square root of the number X; we'll call it N.
2) Set N equal to the ceiling of N (round up to the nearest integer).
3) Test for (X % N). If N divides evenly into X, we found our first number.
if 0, divide X by N to get M. M and N are our numbers
if not 0, increment N by 1 and start step 3 over.
答案 1 :(得分:4)
我已经用user85109在一个详细的函数中重写了上面提出的MATLAB答案,其中有足够的注释和一些更简单的术语。当然非常有效,适用于大量数据,并且希望能够以任何语言轻松编写,该语言提供了用于获得整数的素数因子化的库函数。
function [a, b] = findIntegerFactorsCloseToSquarRoot(n)
% a cannot be greater than the square root of n
% b cannot be smaller than the square root of n
% we get the maximum allowed value of a
amax = floor(sqrt(n));
if 0 == rem(n, amax)
% special case where n is a square number
a = amax;
b = n / a;
return;
end
% Get its prime factors of n
primeFactors = factor(n);
% Start with a factor 1 in the list of candidates for a
candidates = [1];
for i=1:numel(primeFactors)
% get the next prime factr
f = primeFactors(i);
% Add new candidates which are obtained by multiplying
% existing candidates with the new prime factor f
% Set union ensures that duplicate candidates are removed
candidates = union(candidates, f .* candidates);
% throw out candidates which are larger than amax
candidates(candidates > amax) = [];
end
% Take the largest factor in the list d
a = candidates(end);
b = n / a;
end
答案 2 :(得分:3)
请注意,如果X非常大,那么从sqrt(X)开始并一次向下工作一步将是一项悲惨的任务。这可能需要很长时间。
如果你能找到数字的因子,那么只需计算X的所有除数小于sqrt(X)。
考虑数字X = 123456789012345678901234567890。小于sqrt(X)的最小整数是351364182882014,因此简单地递减该值以测试除数可能会有问题。
保理X,我们得到这个主要因素列表:
{2, 3, 3, 3, 5, 7, 13, 31, 37, 211, 241, 2161, 3607, 3803, 2906161}
计算除数小于sqrt(N)是一个相当快的运算,给出了素数因子,得到除数349788919693221,所以我们有
349788919693221 * 352946540218090 = 123456789012345678901234567890
这些是N数最接近的除数。但是,从sqrt(N)开始,我们需要减少多少次?这个区别是:1575263188793,所以超过1.5e12步。
确定指示因子的简单方案(在MATLAB中)
Dmax = 351364182882014;
F = [2, 3, 3, 3, 5, 7, 13, 31, 37, 211, 241, 2161, 3607, 3803, 2906161];
D = 1;
for i = 1:numel(F)
D = kron(D,[1,F(i)]);
D = unique(D);
D(D > Dmax) = [];
end
D(end)
ans =
349788919693221
另一个因素就足够了。如果数字太大而不能超过燧石的动态范围,那么你需要使用一些更高精度算术的变体。
答案 3 :(得分:1)
一个完美的正方形将有一个SQRT(X)的一面,所以从那里开始向下工作。
int X = ...
for(int i=sqrt(x);i>0;i--) {
// integer division discarding remainder:
int j = X/i;
if( j*i == X ) {
// closest pair is (i,j)
return (i,j);
}
}
return NULL;
请注意,只有X
实际上可被两个整数整除时才会起作用(即素数X
最终会以(1,X)
结束)。根据你正在做的事情,你可能最好选择稍大一些的尺寸,然后使它成正方形......即边长为CEILING(SQRT(X))
。
答案 4 :(得分:0)
另一种方法是设置此优化问题
最小化因子X和Y的差异 产品X×Y和P的差异因此,你有一个目标函数加权了两个目标:
min c × |X × Y - P| + d × |X – Y|
subject to X, Y ∈ ℤ
X, Y ≥ 0
其中c,d是非负数,用于定义您估算的目标值。
然而,与sqrt
解决方案很相似:)
答案 5 :(得分:0)
感谢您的回答。我已经创建了一个函数,可以在sqrt方法中找到最接近的3个整数:
function [a, b, c] = findIntegerFactorsCloseToCubeRoot(n)
% a cannot be greater than the cube root of n
% b cannot be smaller than the cube root of n
% we get the maximum allowed value of a
amax = floor(nthroot(n,3))
if amax^3 == n
% special case where n is a cube number
a = amax;
b = a;
c = a;
return;
end
% Get its prime factors of n
primeFactors = factor(n);
% Start with a factor 1 in the list of candidates for a
candidates = [1];
for i=1:numel(primeFactors)
% get the next prime factor
f = primeFactors(i);
% Add new candidates which are obtained by multiplying
% existing candidates with the new prime factor f
% Set union ensures that duplicate candidates are removed
candidates = union(candidates, f .* candidates);
% throw out candidates which are larger than amax
candidates(candidates > amax) = [];
end
% Take the largest factor in the list d
a = candidates(end);
% call similar function for remaining 2 factors
[b, c] = findIntegerFactorsCloseToSqRoot(n/a);
end
答案 6 :(得分:0)
我还不允许发表评论,所以这里是一个基于@Anthony DeSimone 的答案的快速 python>=3.8 实现,修改为使用 @Egor Skriptunoff 建议的 floor():
import math
def sqrt_int(X: int):
N = math.floor(math.sqrt(X))
while bool(X % N):
N -= 1
M = X // N
return M, N