Java 限定此程序以确定不包含零的倒数整数之和
设A表示其十进制表示不包含数字0的正整数集。已知A中元素的倒数之和为23.10345 例1,2,3,4,5,6,7,8,9,11-19,21-29,31-39,41-49,51-59,61-69,71-79,81-89,91-99111-119 然后取每个数字的倒数,求和总数 如何从数值上验证这一点 编写一个计算机程序来验证这个数字 以下是我到目前为止所写的内容,我需要帮助解决此问题,因为目前完成此问题需要的时间太长: Java代码Java 限定此程序以确定不包含零的倒数整数之和,java,math,numerical-methods,numerical-analysis,bounding,Java,Math,Numerical Methods,Numerical Analysis,Bounding,设A表示其十进制表示不包含数字0的正整数集。已知A中元素的倒数之和为23.10345 例1,2,3,4,5,6,7,8,9,11-19,21-29,31-39,41-49,51-59,61-69,71-79,81-89,91-99111-119 然后取每个数字的倒数,求和总数 如何从数值上验证这一点 编写一个计算机程序来验证这个数字 以下是我到目前为止所写的内容,我需要帮助解决此问题,因为目前完成此问题需要的时间太长: Java代码 import java.util.*; public cl
import java.util.*;
public class recip
{
public static void main(String[] args)
{
int current = 0; double total = 0;
while(total < 23.10245)
{
if(Integer.toString(current).contains("0"))
{
current++;
}
else
{
total = total + (1/(double)current);
current++;
}
System.out.println("Total: " + total);
}
}
}
import java.util.*;
公共类recip
{
公共静态void main(字符串[]args)
{
int电流=0;双倍总计=0;
而(总数<23.10245)
{
if(Integer.toString(current).contains(“0”))
{
电流++;
}
其他的
{
总计=总计+(1/(双)电流);
电流++;
}
系统输出打印项次(“总计:+总计);
}
}
}
对于大于某个阈值的电流的所有值N
,1.0/(双)电流
将足够小,使得总
不会因添加1.0/(双)电流
而增加。因此,终止标准应该类似于
while(total != total + (1.0/(double)current))
而不是测试先验已知的极限。当current
达到此特殊值N
时,循环将停止。我怀疑转换为字符串然后检查字符“0”的步骤太长。如果要避免全零,可能有助于增加当前的current
,因此:
(编辑——感谢Aaron McSmooth)
这是未经测试的,但概念应该很清楚:每当你达到十的幂的倍数(例如300或20000),你就加上下一个更低的幂10(在我们的例子中分别是10+1和1000+100+10+1),直到你的数字中不再有零
相应地更改而循环,看看这是否对性能没有帮助,直到您的问题变得可控为止
哦,您可能还想限制一下系统.out
的输出。每十次、百分之一次或10000次迭代就足够了吗
编辑第二条:
睡了一会儿之后,我怀疑我的回答可能有点短视(如果你愿意的话,那就怪时间太晚了)。我只是希望,current
的一百万次迭代能够让您找到解决方案,并将其留在那里,而不是使用log(current)
等计算纠正案例
仔细想想,我发现整个问题有两个问题。一是你的目标数字23.10345对我的口味来说是个小菜一碟。毕竟,您正在添加数千项,如“1/17”、“1/11111”等,并使用无限十进制表示,它们的总和不太可能精确到23.10345。如果某位数值数学专家这么说的话,很好,但我想看看他们得出这个结论的算法
另一个问题与第一个问题有关,涉及有理数的有限内存二进制表示。你可以用它,但我有我的怀疑
所以,基本上,我建议你重新编程数值算法,而不是使用蛮力解。对不起
编辑第三条:
出于好奇,我用C++写了这篇文章来测试我的理论。它现在运行了6分钟,大约14.5次(大约5.5亿次迭代)。我们拭目以待
当前版本为
double total = 0;
long long current = 0, currPowerCeiling = 10, iteration = 0;
while( total < 23.01245 )
{
current++;
iteration++;
if( current >= currPowerCeiling )
currPowerCeiling *= 10;
for( long long power = currPowerCeiling; power >= 10; power = power / 10 )
{
if( ( current % power ) == 0 )
{
current = current + ( power / 10 );
}
}
total += ( 1.0 / current );
if( ! ( iteration % 1000000 ) )
std::cout << iteration / 1000000 << " Mio iterations: " << current << "\t -> " << total << std::endl;
}
std::cout << current << "\t" << total << std::endl;
双倍合计=0;
长电流=0,电流上限=10,迭代=0;
而(总数<23.01245)
{
电流++;
迭代++;
如果(当前>=当前功率上限)
电流功率上限*=10;
用于(长功率=电流功率上限;功率>=10;功率=功率/10)
{
如果((当前功率百分比)==0)
{
电流=电流+(功率/10);
}
}
总+=(1.0/电流);
如果(!(迭代%1000000))
std::cout如何将当前数字存储为字节数组,其中每个数组元素都是数字0-9?这样,您可以非常快速地检测到零(使用==
而不是字符串比较字节。包含)
缺点是你需要自己实现递增,而不是使用++
。你还需要设计一种方法来标记“不存在”的数字,这样你就不会将它们检测为零。为不存在的数字存储-1
听起来是一个合理的解决方案
public class SumOfReciprocalWithoutZero {
public static void main(String[] args) {
int maxSize=Integer.MAX_VALUE/10;
long time=-System.currentTimeMillis();
BitSet b=new BitSet(maxSize);
setNumbersWithZeros(10,maxSize,b);
double sum=0.0;
for(int i=1;i<maxSize;i++)
{
if(!b.get(i))
{
sum+=1.0d/(double)i;
}
}
time+=System.currentTimeMillis();
System.out.println("Total: "+sum+"\nTimeTaken : "+time+" ms");
}
static void setNumbersWithZeros(int srt,int end,BitSet b)
{
for(int j=srt;j<end;j*=10)
{
for(int i=1;i<=10;i++)
{
int num=j*i;
b.set(num);
}
if(j>=100)
setInbetween(j, b);
}
}
static void setInbetween(int strt,BitSet b)
{
int bitToSet;
bitToSet=strt;
for(int i=1;i<=10;i++)
{
int nxtInt=-1;
while((nxtInt=b.nextSetBit(nxtInt+1))!=strt)
{
b.set(bitToSet+nxtInt);
}
nxtInt=-1;
int lim=strt/10;
while((nxtInt=b.nextClearBit(nxtInt+1))<lim)
{
b.set(bitToSet+nxtInt);
}
bitToSet=strt*i;
}
}
}
更新:
Total: 13.722766931560747
TimeTaken : 60382 ms
先前已删除答案的Java移植:
public static void main(String[] args) {
long current =11;
double tot=1 + 1.0/2 + 1.0/3 + 1.0/4 + 1.0/5 + 1.0/6 + 1.0/7 + 1.0/8 + 1.0/9;
long i=0;
while(true)
{
current=next_current(current);
if(i%10000!=0)
System.out.println(i+" "+current+" "+tot);
for(int j=0;j<9;j++)
{
tot+=(1.0/current + 1.0/(current + 1) + 1.0/(current + 2) + 1.0/(current + 3) + 1.0/(current + 4) +
1.0/(current + 5) + 1.0/(current + 6) + 1.0/(current + 7) + 1.0/(current + 8));
current += 10;
}
i++;
}
}
static long next_current(long n){
long m=(long)Math.pow(10,(int)Math.log10(n));
boolean found_zero=false;
while(m>=1)
{
if(found_zero)
n+=m;
else if((n/m)%10==0)
{
n=n-(n%m)+m;
found_zero=true;
}
m=m/10;
}
return n;
}
publicstaticvoidmain(字符串[]args){
长电流=11;
双重总和=1+1.0/2+1.0/3+1.0/4+1.0/5+1.0/6+1.0/7+1.0/8+1.0/9;
长i=0;
while(true)
{
电流=下一个_电流(电流);
如果(i%10000!=0)
系统输出打印项次(i+“”+电流+“”+tot);
对于(int j=0;j=1)
{
如果(找到零)
n+=m;
如果((n/m)%10==0,则为else)
{
n=n-(n%m)+m;
发现0=真;
}
m=m/10;
}
返回n;
}
如果处理得当,这并不难
例如,假设您希望找到以123开始(即最左边的数字)并以k个非零数字结束的所有整数的倒数之和。显然有9k个这样的整数,每个整数的倒数在1/(124*10k)…1/(123*10k)范围内因此,所有这些整数的倒数之和以(9/10)k/124和(9/10)k为界
public static void main(String[] args) {
long current =11;
double tot=1 + 1.0/2 + 1.0/3 + 1.0/4 + 1.0/5 + 1.0/6 + 1.0/7 + 1.0/8 + 1.0/9;
long i=0;
while(true)
{
current=next_current(current);
if(i%10000!=0)
System.out.println(i+" "+current+" "+tot);
for(int j=0;j<9;j++)
{
tot+=(1.0/current + 1.0/(current + 1) + 1.0/(current + 2) + 1.0/(current + 3) + 1.0/(current + 4) +
1.0/(current + 5) + 1.0/(current + 6) + 1.0/(current + 7) + 1.0/(current + 8));
current += 10;
}
i++;
}
}
static long next_current(long n){
long m=(long)Math.pow(10,(int)Math.log10(n));
boolean found_zero=false;
while(m>=1)
{
if(found_zero)
n+=m;
else if((n/m)%10==0)
{
n=n-(n%m)+m;
found_zero=true;
}
m=m/10;
}
return n;
}
def approx(t,k):
"""Returns a lower bound and an upper bound on the sum of reciprocals of
positive integers starting with t not containing 0 in its decimal
representation.
k is the recursion depth of the search, i.e. we append k more digits
to t, before approximating the sum. A larger k gives more accurate
results, but takes longer."""
if k == 0:
return 10.0/(t+1), 10.0/t
else:
if t > 0:
low, up = 1.0/t, 1.0/t
else:
low, up = 0, 0
for i in range(10*t+1, 10*t+10):
l,u = approx(i, k-1)
low += l
up += u
return low, up
class c_advance_to_next_non_zero_decimal
{
public:
c_advance_to_next_non_zero_decimal(): next(0), max_set_digit_index(0)
{
std::fill_n(digits, digit_count, 0);
return;
}
int advance_to_next_non_zero_decimal()
{
assert((next % 10) == 0);
int offset= 1;
digits[0]+= 1;
for (int digit_index= 1, digit_value= 10; digit_index<=max_set_digit_index; ++digit_index, digit_value*= 10)
{
if (digits[digit_index]==0)
{
digits[digit_index]= 1;
offset+= digit_value;
}
}
next+= offset;
return next;
}
int advance_to_next_zero_decimal()
{
assert((next % 10)!=0);
assert(digits[0]==(next % 10));
int offset= 10 - digits[0];
digits[0]+= offset;
assert(digits[0]==10);
// propagate carries forward
for (int digit_index= 0; digits[digit_index]==10 && digit_index<digit_count; ++digit_index)
{
digits[digit_index]= 0;
digits[digit_index + 1]+= 1;
max_set_digit_index= max(digit_index + 1, max_set_digit_index);
}
next+= offset;
return next;
}
private:
int next;
static const size_t digit_count= 10; // log10(2**31)
int max_set_digit_index;
int digits[digit_count];
};