Algorithm 将整数表示为一系列乘法器
向下滚动查看最新编辑,我将所有文本都留在这里,这样我就不会使这个问题迄今为止收到的答复无效强>Algorithm 将整数表示为一系列乘法器,algorithm,language-agnostic,Algorithm,Language Agnostic,向下滚动查看最新编辑,我将所有文本都留在这里,这样我就不会使这个问题迄今为止收到的答复无效 我有一个脑筋急转弯,我想得到一个解决方案,我试图解决这个问题,但由于我在数学上并没有那么高的平均水平(也就是说,我认为我非常接近平均水平),我似乎无法理解这一点 问题是:给定的数字x应该被分成一系列的乘数,其中每个乘数=y,将y存储到乘数,然后x=x-y 当x
我有一个脑筋急转弯,我想得到一个解决方案,我试图解决这个问题,但由于我在数学上并没有那么高的平均水平(也就是说,我认为我非常接近平均水平),我似乎无法理解这一点 问题是:给定的数字
x
应该被分成一系列的乘数
,其中每个乘数=y
,将y
存储到乘数
,然后x=x-y
x
时,将x
存储到乘法器
- 必须使用64位长
- 必须返回一个32位整数的数组(…嗯,也可以使用短整数)
- 虽然支持有符号的数字(+和-)会很好,但如果它有助于完成任务,则必须只支持无符号数字
- 结果数组中的每个整数都应小于或等于y,包括最后一个数字
- 是的,最后一个数字只是一个神奇的数字
- 不,这不是模数,因为在大多数情况下,第二个数会大于y
- 是的,大多数可用数字都有多个答案,但是我正在寻找数学运算量最少的答案。就我的逻辑而言,这意味着找到尽可能大的乘数的最大数量,例如
是x=1000000,y=100
,尽管100*100*100
在数学上同样正确10*10*10*10*10
100、121、282
表示为100+21+161
可能是一种方法,但字符串长度的节省充其量是可以忽略的,如果数字之间的距离不是很近,那么效果就不太好。基本上我想要超过10%
所以我想出了一个主意,如果我用一个公共属性,比如一个乘法器,把这些数字分组,然后把剩下的数字除以各个分量,我就可以把它们表示成一个字符串了。这就是问题所在,例如,我认为1000000和100000可以表示为10^(5|6),但由于我的目标用法的上下文,这有点太离谱了:
上下文是Web。特定的RESTful URL:s。这就是为什么我提到考虑使用64个字符(网络安全的字母数字非保留字符,然后是一些字符),因为那时我可以创建看似随机的URL,这些URL可以解压为表示一组id号的整数列表。在这一点上,我想创建一个类似于base 64的数字系统来表示基数为10/2的数字,但由于我不是一个数学天才,因此除了这一点,我不知道如何做到这一点
赏金
现在,我已经写了整个故事(很抱歉,这是一个很长的故事),我开始悬赏这个问题。关于前面指定的首选算法的所有要求仍然有效。我还想说,我已经很感激迄今为止我收到的所有答案,我喜欢被证明是错误的,如果它以你们这样的方式做的话
结论
好吧,赏金现在已经给了。我将一些评论散布到回应中,主要是为了将来的参考和我自己,如果你认为我们应该能够在多个答案中传播,你也可以查看我关于传播赏金的建议,这与这个问题相关
感谢大家抽出时间回答这个模数不是很强吗 设
/
为整数除法(整数),%
为模
int result[3];
result[0] = y;
result[1] = x / y;
result[2] = x % y;
就像我在上面的评论一样,我不确定我是否完全理解这个问题。但是假设整数(n和给定的y),这应该适用于您所述的情况:
multipliers[0] = n / y;
multipliers[1] = y;
addedNumber = n % y;
只需设置x:=x/n,其中n是小于x和y的最大数。当您以x结束时,请在最终解释后编辑: 我认为base64是最好的解决方案,因为有处理它的标准函数,而这种想法的变体并没有带来太多改进。这里的其他人对此作出了更详细的回答 关于最初的问题,虽然该准则有效,但不能保证
shortest_output = {}
foreach (int R = 0; R <= X; R++) {
// iteration over possible remainders
// check if the rest of X can be decomposed into multipliers
newX = X - R;
output = {};
while (newX > Y) {
int i;
for (i = Y; i > 1; i--) {
if ( newX % i == 0) { // found a divider
output.append(i);
newX = newX /i;
break;
}
}
if (i == 1) { // no dividers <= Y
break;
}
}
if (newX != 1) {
// couldn't find dividers with no remainder
output.clear();
}
else {
output.append(R);
if (output.length() < shortest_output.length()) {
shortest_output = output;
}
}
}
int[] IDs;
IDs.sort() // So IDs[i] is always smaller or equal to IDs[i-1].
string url = Base64Encode(IDs[0]);
for (int i = 1; i < IDs.length; i++) {
url += "," + Base64Encode(IDs[i-1] - IDs[i]);
}
public final class PrimeNumberException extends Exception {
private final long primeNumber;
public PrimeNumberException(long x) {
primeNumber = x;
}
public long getPrimeNumber() {
return primeNumber;
}
}
public static Long[] decompose(long x, long y) {
try {
final ArrayList<Long> operands = new ArrayList<Long>(1000);
final long rest = x % y;
// Extract the rest so the reminder is divisible by y
final long newX = x - rest;
// Go into recursion, actually it's a tail recursion
recDivide(newX, y, operands);
} catch (PrimeNumberException e) {
// return new Long[0];
// or do whatever you like, for example
operands.add(e.getPrimeNumber());
} finally {
// Add the reminder to the array
operands.add(rest);
return operands.toArray(new Long[operands.size()]);
}
}
// The recursive method
private static void recDivide(long x, long y, ArrayList<Long> operands)
throws PrimeNumberException {
while ((x > y) && (y != 1)) {
if (x % y == 0) {
final long rest = x / y;
// Since y is a divisor add it to the list of operands
operands.add(y);
if (rest <= y) {
// the rest is smaller than y, we're finished
operands.add(rest);
}
// go in recursion
x = rest;
} else {
// if the value x isn't divisible by y decrement y so you'll find a
// divisor eventually
if (--y == 1) {
throw new PrimeNumberException(x);
}
}
}
}
public static Long[] decompose(long x, long y) {
final ArrayList<Long> operands = new ArrayList<Long>();
final long rest = x % y;
// Extract the rest so the reminder is divisible by y
final long newX = x - rest;
// Go into recursion, actually it's a tail recursion
recDivide(newX, y, operands);
// Add the reminder to the array
operands.add(rest);
return operands.toArray(new Long[operands.size()]);
}
// The recursive method
private static void recDivide(long newX, long y, ArrayList<Long> operands) {
long x = newX;
if (x % y == 0) {
final long rest = x / y;
// Since y is a divisor add it to the list of operands
operands.add(y);
if (rest <= y) {
// the rest is smaller than y, we're finished
operands.add(rest);
} else {
// the rest can still be divided, go one level deeper in recursion
recDivide(rest, y, operands);
}
} else {
// if the value x isn't divisible by y decrement y so you'll find a divisor
// eventually
recDivide(x, y-1, operands);
}
}
0 to
18,446,744,073,709,551,616
-9,223,372,036,854,775,808 to
9,223,372,036,854,775,807
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789$-_.+!*'(),
Range (bytes) Chars Base64 chars Compression ratio
------------- ----- ------------ -----------------
< 10 (1) 1 2 -100%
< 100 (1) 2 2 0%
< 1000 (2) 3 3 0%
< 10^4 (2) 4 3 25%
< 10^5 (3) 5 4 20%
< 10^6 (3) 6 4 33%
< 10^7 (3) 7 4 42%
< 10^8 (4) 8 6 25%
< 10^9 (4) 9 6 33%
< 10^10 (5) 10 7 30%
< 10^11 (5) 11 7 36%
< 10^12 (5) 12 7 41%
< 10^13 (6) 13 8 38%
< 10^14 (6) 14 8 42%
< 10^15 (7) 15 10 33%
< 10^16 (7) 16 10 37%
< 10^17 (8) 17 11 35%
< 10^18 (8) 18 11 38%
< 10^19 (8) 19 11 42%
< 2^64 (8) 20 11 45%
>>> import time
>>> def test():
... before = time.time()
... print factor(2**32-1, 256)
... print time.time()-before
...
>>> test()
[254, 232, 215, 113, 3, 15]
1.68499994278
>>> 254*232*215*113*3+15
4294967295L
def factor(x, y):
# y should be smaller than x. If x=y then {y, 1, 0} is the best solution
assert(x > y)
best_output = []
# try all possible remainders from 0 to y
for remainder in xrange(y+1):
output = []
composite = x - remainder
factors = getFactors(composite)
# check if any factor is larger than y
bad_remainder = False
for n in factors.iterkeys():
if n > y:
bad_remainder = True
break
if bad_remainder: continue
# make the best factors
while True:
results = largestFactors(factors, y)
if results == None: break
output += [results[0]]
factors = results[1]
# store the best output
output = output + [remainder]
if len(best_output) == 0 or len(output) < len(best_output):
best_output = output
return best_output
# Heuristic
# The bigger the number the better. 8 is more compact than 2,2,2 etc...
# Find the most factors you can have below or equal to y
# output the number and unused factors that can be reinserted in this function
def largestFactors(factors, y):
assert(y > 1)
# iterate from y to 2 and see if the factors are present.
for i in xrange(y, 1, -1):
try_another_number = False
factors_below_y = getFactors(i)
for number, copies in factors_below_y.iteritems():
if number in factors:
if factors[number] < copies:
try_another_number = True
continue # not enough factors
else:
try_another_number = True
continue # a factor is not present
# Do we want to try another number, or was a solution found?
if try_another_number == True:
continue
else:
output = 1
for number, copies in factors_below_y.items():
remaining = factors[number] - copies
if remaining > 0:
factors[number] = remaining
else:
del factors[number]
output *= number ** copies
return (output, factors)
return None # failed
# Find prime factors. You can use any formula you want for this.
# I am using elliptic curve factorization from http://sourceforge.net/projects/pyecm
import pyecm, collections, copy
getFactors_cache = {}
def getFactors(n):
assert(n != 0)
# attempt to retrieve from cache. Returns a copy
try:
return copy.copy(getFactors_cache[n])
except KeyError:
pass
output = collections.defaultdict(int)
for factor in pyecm.factors(n, False, True, 10, 1):
output[factor] += 1
# cache result
getFactors_cache[n] = output
return copy.copy(output)
import math
def entropy():
num = 2**32
probability = 1./num
return -(num) * probability * math.log(probability, 2)
# the (num) * probability cancels out
def longTo64(num):
mapping = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
output = ""
# special case for 0
if num == 0:
return mapping[0]
while num != 0:
output = mapping[num % 64] + output
num /= 64
return output
def longTo85(num):
mapping = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~!*'();:@&=+$,/?%#[]"
output = ""
base = len(mapping)
# special case for 0
if num == 0:
return mapping[0]
while num != 0:
output = mapping[num % base] + output
num /= base
return output
def stringToLong(string):
mapping = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~!*'();:@&=+$,/?%#[]"
output = 0
base = len(mapping)
place = 0
# check each digit from the lowest place
for digit in reversed(string):
# find the number the mapping of symbol to number, then multiply by base^place
output += mapping.find(digit) * (base ** place)
place += 1
return output
import base64
import pickle
# get some long list of numbers
a = (854183415,1270335149,228790978,1610119503,1785730631,2084495271,
1180819741,1200564070,1594464081,1312769708,491733762,243961400,
655643948,1950847733,492757139,1373886707,336679529,591953597,
2007045617,1653638786)
# this gets you the url-safe string
str64 = base64.urlsafe_b64encode(pickle.dumps(a,-1))
print str64
>>> gAIoSvfN6TJKrca3S0rCEqMNSk95-F9KRxZwakqn3z58Sh3hYUZKZiePR0pRlwlfSqxGP05KAkNPHUo4jooOSixVFCdK9ZJHdEqT4F4dSvPY41FKaVIRFEq9fkgjSvEVoXdKgoaQYnRxAC4=
# this unwinds it
a64 = pickle.loads(base64.urlsafe_b64decode(str64))
print a64
>>> (854183415, 1270335149, 228790978, 1610119503, 1785730631, 2084495271, 1180819741, 1200564070, 1594464081, 1312769708, 491733762, 243961400, 655643948, 1950847733, 492757139, 1373886707, 336679529, 591953597, 2007045617, 1653638786)
10^9 (4 characters) = 1000000000 (10 characters)
7829203478 = some random number...
bool negative=(n<1)?true:false;
int j=n%y;
if(n==0 || n==1)
{
list.append(n);
return;
}
while((long64)(n-j*y)>MAX_INT && y>1) //R has to be stored in int32
{
y--;
j=n%y;
}
if(y<=1)
fail //Number has no suitable candidate factors. This shouldn't happen
int i=0;
for(;i<j;i++)
{
list.append(y);
}
list.append(n-y*j);
if(negative)
list[0]*=-1;
return;