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

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 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];
};