Java 数学学习手册(二)

A4纸制作125厘米长尺:设计原理与DIY实践指南 在工程制图、数学教学和家庭DIY中,精确测量是基础需求。传统尺具受限于长度和便携性,而利用A4纸通过模块化设计和拼接原理,可以低成本实现长尺度测量工具。其技术价值在于将数字设计(矢量软件精确控制)与物理制作(材料力学)结合,解决了临时测量、教育实践和资源受限场景下的工具需求。应用场景涵盖课堂长度单位教学、手工模型制作、家庭应急测量等。本文以125厘米纸尺为例,详解从A4纸排版、刻度系统设计到打印拼接的全流程,涉及Inkscape矢量绘图和材料优化等热词,为STEAM教育和实用DIY提供可复制的方案。 阅读详情

原文:Learn Java with Math

协议:CC BY-NC-SA 4.0

十三、Java 基础项目

  1. 编写代码打印出下图。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 编写代码来绘制以下形状。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 写代码做这个三角形。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 写一个函数来检查一个整数是否能被另一个整数整除。

    例如:

    (1)给定输入 10,5,输出为“是,2”;

    (2)给定输入 11,2,输出为"否";

  2. 写 Java 代码画圣诞树。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 写代码找出给定正整数的所有因子。

    例如,当用户输入“10”时,你的程序应该输出 1,2,5,10

  2. 编写一个方法,该方法接受一个月(即 1 到 12 之间的整数)作为参数,并返回当前年份中该月的天数。

  3. 编写代码,生成从控制台输入的两个数字的乘积:

    请输入两个数进行乘法运算

    下一个数字- > 7

    下一个数字- > 15

    产品= 105

  4. 写一个检查正整数是否是质数的方法。

  5. 编写一个方法,将一个整数转换成用二进制表示的字符串。例如,给定一个参数“19”,它应该返回“10011”。

十四、Java 基础解决方案

以下是本书 Java 基础部分前几章的解决方案。

第章第五章:变量

  1. 数字电子设备的信号(开/关)

  2. OOP 基于类;国际网络路跑联盟

  3. (e)

  4. (b)

第七章:输入和输出

  1. name     age    height
    Anthony  17     5'9"
    Belly    17     5'6"
    Bighead  16     6'
    
    
  2. a   b   c
    \\
    '
    """
    
    

第八章:循环结构–For 循环

  1. 内部循环有三次迭代,没有回车;外部循环有两次迭代。

  2. 减去一个后,你会发现一个清晰的模式。

  3. 立方数模式

  4. 所有数字加 1

  5. 嵌套循环

第九章:循环结构–While 循环

  1. 永远(死循环)

  2. 三次,x = 2,4,16

  3. 五次,最终输出是“bbbbbabbbbb”

  4. 六次,当 x = 100,50,25,12,6,3

  5. 8 3 ←中间有个空格

第十章:逻辑控制结构

十五、莱特兄弟的掷硬币游戏

编程帮助我们理解和解释许多复杂的问题。你可以找到一个有趣的在线视频,“抛硬币难题”,它讲述了一个历史故事,并用分析方法解释了一个概率问题的解决方案。这个故事是关于莱特兄弟,奥维尔和威尔伯,他们玩抛硬币游戏来决定谁应该首先开始新的飞行实验。他们连续掷硬币,直到奥维尔连续得到双头,或者威尔伯在“相邻”序列中得到一个头和一个尾。虽然视频使用了概率和代数概念来计算莱特兄弟的获胜优势,但我们将尝试使用 Java 编程进行实验。下面的方法模拟了莱特兄弟的游戏,并分析了他们的结果(注意有用的注释,用//标记,这样我们可以更容易地阅读代码)。

private static int count_a, count_b, count_ab = 0;
private static int totalsteps_a, totalsteps_b = 0;

/// whoever gets below pattern first wins, or tie if both of them reach targeted patterns at the same round
/// a: HH wins; b: HT wins; Use boolean 'true': head, 'false': tail
public static void flipCoin()
{
       Random r = new Random();
       /// initial value, or first round result
       boolean current_a = r.nextBoolean();
       boolean current_b = r.nextBoolean();

       boolean win_a = false;
       boolean win_b = false;
       int round = 1;
       while(true) {
              round++;
              boolean next_a = r.nextBoolean();
              boolean next_b = r.nextBoolean();
              if (current_a && next_a) {
                     win_a = true;
              }
              if (current_b && !next_b) {
                     win_b = true;
              }
              if (win_a && win_b) {
                     System.out.println("Both WIN! - round: " + round);

                     count_ab++;
                     totalsteps_a += round;
                     totalsteps_b += round;
                     break;
              }
              if (win_a && !win_b) {
                     System.out.println("A WIN! - round: " + round);
                     count_a++;
                     totalsteps_a += round;
                     break;
              }
              if (!win_a && win_b) {
                     System.out.println("B WIN! - round: " + round);
                     count_b++;
                     totalsteps_b += round;
                     break;
              }
              current_a = next_a;
              current_b = next_b;
       }
}

使用下面的main方法,我们可以收集样本并得到统计摘要。

public static void main(String[] args) {
       final int MAX = 10000;
       for(int i=0; i < MAX; i++) {
              flipCoin();
       }
       System.out.println("Summary");
       System.out.println("Total samples: " + MAX);
       System.out.println("Winning counts: a - " + count_a + "; b - " + count_b + "; ab - " + count_ab);
       int probability_a = count_a * 100 / (count_a + count_b);
       int probability_b = count_b * 100 / (count_a + count_b);
       System.out.println("Winning probability: HH=" + probability_a + "%; HT=" + probability_b + "%.");
       double average_a = totalsteps_a / (count_a + count_ab);
       double average_b = totalsteps_b / (count_b + count_ab);
       System.out.println("Average rounds to win: HH=" + average_a + "; HT=" + average_b + ".");
}

在我们用不同的参数运行了许多实验之后,我们了解了实际发生的情况,然后可以得出结论,威尔伯赢得赌注的机会明显更高(大约 62%比 37%)。输出应该如下所示。

.........
B WIN! - round: 3
A WIN! - round: 2
A WIN! - round: 3
B WIN! - round: 2
B WIN! - round: 4
A WIN! - round: 4
B WIN! - round: 2
B WIN! - round: 2
B WIN! - round: 3
B WIN! - round: 2
A WIN! - round: 2
A WIN! - round: 2
Both WIN! - round: 2
B WIN! - round: 3
Summary
Total samples: 10000

Winning counts: a - 3213; b - 5386; ab - 1401
Winning probability: HH=37%; HT=62%.
Average rounds to win: HH=2.0; HT=3.0.

十六、毕达哥拉斯三元组

勾股定理在小学到中学的学生中是众所周知的,因为它看起来很优雅,适用于所有的直角三角形。

数学:毕达哥拉斯三元组

在直角三角形内,a 和 b 是两条边,c 是斜边。

  • a2+b2= c2

当 a,b,c 是满足勾股定理的正整数时,(a,b,c)称为“勾股三元组”。显然(3,4,5)是第一个毕达哥拉斯三元组,接下来是(5,12,13),(6,8,10),以此类推。毕达哥拉斯三元组的数目是无限的。

例子

那么,我们如何找到所有低于 100 的毕达哥拉斯三元组呢?

回答

我们可以将(3,4,5)乘以任意整数得到(6,8,10),(9,12,15),…,(57,76,95)。我们可以用(5,12,13)作为另一个基三元组得到(10,24,26),…,(35,84,91)。等等。

但是这种方法将要求我们首先找出所有的基本毕达哥拉斯三元组。因此,我们基本上必须检查 a 的每个小于 100 的正整数,然后计算 b 和 c,假设 a < b < c。顺便说一下,a = b 是不可能的。然而,有了编程方法,它不再是一个具有挑战性的数学问题。

这是找出满足勾股定理的所有可能三元组(a,b,c)的方法。

       private static int allPythagoreanNumbers(int upperBound) {
              int count = 0;
              for(int a = 1; a < upperBound; a++) {
                     for(int b = a; b < upperBound; b++) {
                            for(int c = b; c < upperBound; c++) {
                                   if (a * a + b * b == c * c) {
                                          System.out.println("("+a+", "+b+", "+c+")");
                                          count++;
                                   }
                            }
                     }
              }
              return count;
       }

       public static void main(String[] args) {
              System.out.println("Total count: " + allPythagoreanNumbers(100));
       }

它将输出如下内容:

  • (3, 4, 5)

  • (5, 12, 13)

  • (6, 8, 10)

  • (7, 24, 25)

  • (8, 15, 17)

  • (9, 12, 15)

  • (9, 40, 41)

  • (10, 24, 26)

  • (11, 60, 61)

  • (12, 16, 20)

  • (12, 35, 37)

  • (13, 84, 85)

  • (14, 48, 50)

  • (15, 20, 25)

  • (15, 36, 39)

  • (16, 30, 34)

  • (16, 63, 65)

  • (18, 24, 30)

  • (18, 80, 82)

  • (20, 21, 29)

  • (20, 48, 52)

  • (21, 28, 35)

  • (21, 72, 75)

  • (24, 32, 40)

  • (24, 45, 51)

  • (24, 70, 74)

  • (25, 60, 65)

  • (27, 36, 45)

  • (28, 45, 53)

  • (30, 40, 50)

  • (30, 72, 78)

  • (32, 60, 68)

  • (33, 44, 55)

  • (33, 56, 65)

  • (35, 84, 91)

  • (36, 48, 60)

  • (36, 77, 85)

  • (39, 52, 65)

  • (39, 80, 89)

  • (40, 42, 58)

  • (40, 75, 85)

  • (42, 56, 70)

  • (45, 60, 75)

  • (48, 55, 73)

  • (48, 64, 80)

  • (51, 68, 85)

  • (54, 72, 90)

  • (57, 76, 95)

  • (60, 63, 87)

  • (65, 72, 97)

  • 总数:50

这只是我们如何使用程序解决问题的众多演示之一。

问题

  1. 在示例中,我们使用三个for-循环从 1 到 99 迭代 a、b、c。你如何通过减少到两个for-循环来改进它?

  2. 利用例子中的思想,我们如何找出所有小于 100 的毕达哥拉斯素数?毕达哥拉斯素数解释如下。

数学:毕达哥拉斯质数

毕达哥拉斯素数是两个平方的和。并且,它需要是 4n + 1 的形式,其中 n 是正整数。毕达哥拉斯素数的例子有 5,13,17,29,37 和 41。

印度人

利用示例代码,看看如何进行小的更改来找到解决方案。

十七、强类型编程

正如我们在本书第一部分开始时了解到的,Java 编程语言已经定义了整数、双精度、布尔、字符串等。,作为基本类型。在 Java 中,如果没有预先定义变量的类型,我们就不能给变量赋值。只有在一个变量被一个类型明确定义后,例如,integer,我们才被允许给它分配一个整数值,并开始在计算中使用它作为一个整数。从逻辑上讲,一旦定义了变量的类型,就不能再给它赋不同类型的值。例如,如果一个变量被定义为布尔值,它就不能被赋予整数值。否则,我们将得到一个类型不匹配的编译错误。

铅字铸造

但是,如果一个变量被定义为 double,我们怎么给它赋一个整数值呢?让我们做一些实验。

       public static void main(String[] args) {
              double a = 5;
              System.out.println(a);
              double b = 3 * 5;
              System.out.println(b);
              double x = 5 / 3;
              System.out.println(x);
              double y = (double)(5 / 3);
              System.out.println(y);
              double z = (double)5 / 3;
              System.out.println(z);
              double t = 5.0 / 3;
              System.out.println(t);
              double u = 5 / 3d;
              System.out.println(u);
       }

这是输出:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

下面的模式是我们从这个实验中学到的:

  • 当整数 5 被赋给双精度类型变量时,该变量将得到一个带小数点表示的等效值,即 double value 5.0。

  • 当一个整数除以另一个整数时,结果遵循相同的整数类型,例如 5 / 3 = 1。但是,当分数“5 / 3”被赋给双精度类型变量时,结果值将自动转换为双精度值 1.0。

  • (double)(5 / 3)将(5/ 3)的整数结果转换为双精度值。这叫做类型转换。结果是 1.0,一个双精度值。

我们如何从 5 / 3 得出一个精确的值?诀窍是用(double)5 / 3,而不是5 / 3。(double)5 / 3的结果是一个双精度值。或者,您可以使用 5.0 / 3 来产生相同的结果。另一种方式是5d / 3,或5 / 3d。两个表达式的结果都是相同的双精度值。

数学:直线的斜率

在 x-y 2D 笛卡尔坐标系中,点(x1,y1)和(x2,y2)之间的直线的斜率等于(y2 - y1) / (x2 - x1)。

例子

实现一个名为double getSlope()的公共方法,该方法返回一条线的斜率。如果两个点有相同的 x 坐标,分母为零,斜率未定义,所以在这种情况下应该抛出一个IllegalArgumentException。这将停止您的程序运行,并显示指定的错误信息。

回答

在一个Line类中,我们定义了两个点和一个构造函数:

       private Point p1;
       private Point p2;
       public Line(Point p1, Point p2) {
              this.p1 = p1;
              this.p2 = p2;
       }

Point类被设计为:

public class Point {
       private int x;
       private int y;
       public Point() {
       }

       public void setX(int x) {
              this.x = x;
       }

       public int getX() {
              return x;
       }

       public void setY(int y) {
              this.y = y;
       }

       public int getY() {
              return y;
       }
}

现在我们在Line类中添加一个名为getSlope()的方法。

public double getSlope() {
       if (this.p1.getX() == this.p2.getX()) {
              throw new IllegalArgumentException("Denominator cannot be 0");
       }
       return (double)(this.p2.getY() - this.p1.getY()) / (this.p2.getX() - this.p1.getX());
}

该方法看起来很容易,但棘手的部分是我们将两个整数相除的结果转换为 double 值,也就是说,

(double)(this.p2.getY() - this.p1.getY()) / (this.p2.getX() - this.p1.getX())

数学:共线性

如果可以画一条直线来连接点,那么这些点就是共线的。两个基本的例子是三个点具有相同的 x 或 y 坐标。更一般的情况可以通过计算每对点之间的直线的斜率并检查所有对点的斜率是否相同来确定。

我们使用公式(y2 - y1) / (x2 - x1)来确定两点(x1,y1)和(x2,y2)之间的斜率。

将以下方法添加到您的Line类中:

public boolean isCollinear(Point p)

如果给定点与这条线的点共线,它需要返回 true。

十八、条件语句

如何识别和表示 x 和 y 这两个数中较大的那个数?

数学:假设和结论

在数学公式中,我们必须引入绝对符号来构成表达式:

x 和 y 之间较大的数字外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

回忆一下if / else结构:

if (x >= y) {
       // x is the bigger number
} else {
       // y is the bigger number
}

它非常简单易懂。

if / else结构遵循从假设到结论的常见实验。

       if (<Hypothesis>) {
              <Conclusion>
       } else {              // the hypothesis is NOT valid
              <Different conclusion>
       }

<Hypothesis>部分需要是一个布尔值,在一个数学表达式中可以包含一个变量或多个变量。

条件语句有几种类型的结构(有些你已经见过,有些对你来说是新的)。

  • 简单的if,或if / else子句。

  • 稍微复杂一点的if / else if阶梯。

    if (...) {
           ......
    } else if (...) {
           ......
    } else if (...) {
           ......
    } else {
           ......
    }
    
    
  • 嵌套的if / else语句。

    if (...) {
           ......
    } else {
           if (...) {
                  ......
           } else {
                  ......       ......
           }
    }
    
    

最后一种模式用于实现树状结构。当我们决定使用哪种模式时,这将取决于我们所解决的问题的类型。

例子

下面这段代码有什么问题吗?

       if (i > 50) {
              <do something...>
       } else if (i > 100) {
              <do something...>
       } else {
              <do something...>
       }

回答

当i <= 50的时候,永远不会是i > 100,所以中间的else if分支其实是一条死路。一个简单的修正应该是交换代码中“50”和“100”的位置。而且注意这个,当它在下面的代码块中说else if (i > 50) {...}的时候,实际上是指 50 < i < = 100。

       if (i > 100) {
              <do something...>
       } else if (i > 50) {
              <do something...>
       } else {
              <do something...>
       }

例子

创建一种将学生的分数(0 到 100 的整数)映射到标准 GPA 分数的方法。

回答

第一种解决方案(v0)使用了几个if子句。问题是,例如,当分数为 69 时,它必须执行所有四个if条款。这不是一个有效的方法。

       public static char getGpaScore_v0(int points) {
              if (points > 89) {
                     return 'A';
              }
              if (points < 90 && points > 79)       {
                     return 'B';
              }
              if (points < 80 && points > 69)       {
                     return 'C';
              }
              if (points < 70 && points > 64)       {
                     return 'D';
              }
              // if (points < 65) <-- this line can be omitted
              return 'F';
       }

第二个解决方案(v1)利用了一个嵌套的"if / else"语句。它解决了从早期版本中观察到的问题- v0。

       public static char getGpaScore_v1(int points) {
              if (points > 89) {
                     return 'A';
              } else {
                     if (points > 79) {
                            return 'B';
                     } else {
                            if (points > 69) {
                                   return 'C';
                            } else {
                                   if (points > 64) {
                                          return 'D';
                                   } else {
                                          return 'F';
                                   }
                            }
                     }
              }
       }

为了给代码结构提供更好的可读性,引入了第三种解决方案(v2),如下所示。

       /*
        * 90 to 100 --- A
        * 80 to 89        --- B
        * 70 to 79        --- C
        * 65 to 69  --- D
        * below 65  --- F
        */
       public static char getGpaScore_v2(int points) {
              if (points > 89) {
                     return 'A';
              } else if (points > 79) {
                     return 'B';
              } else if (points > 69) {
                     return 'C';
              } else if (points > 64) {
                     return 'D';
              } else {
                     return 'F';
              }
       }

数学:象限

在笛卡尔坐标系中,象限由 x 和 y 坐标是正数还是负数决定。有四个象限,由 x 轴和 y 轴分隔。具体来说,所有的点(x > 0,y > 0)都属于象限 I(或第 1 象限);所有的点(x < 0, y > 0)都属于第二象限(或第二象限);所有点(x < 0, y < 0) belong to quadrant III (or 3rd quadrant); and all the points (x > 0,y < 0)属于象限 IV(或第四象限)

例子

能不能写一个方法来识别任意给定点(x,y)在坐标系上属于哪个象限?x 和 y 都是实数。如果一个点落在 x 轴或 y 轴上,那么该方法应该返回 0。

回答

在这个例子中有两个变量,x和y,。将 x 和 y 定义为浮点数类型。进行如下所示的案例分析:

情况 1:当一个点落在 x 轴或 y 轴上时外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 y = 0 或 x = 0

情况 2:当一个点落在第一象限外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 x > 0,y > 0 时

情况 3:当一个点落在第二象限外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 x < 0,y > 0 时

情况 4:当一个点落在第三象限外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 x < 0,y < 0 时

情况 5:当一个点落在第四象限外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 x > 0,y < 0 时

将情况 2 和情况 5 组合成 x > 0 的类别,将情况 3 和情况 4 组合成 x < 0 的类别,产生如下代码结构:

       private static int quadrant(float x, float y) {
              if (x == 0 || y == 0) {
                     return 0;
              }
              else if (x > 0)              // x > 0 and y <> 0
              {
                     if (y > 0) {
                            return 1;
                     }
                     return 4;
              }
              else                         // x < 0 and y <> 0
              {
                     if (y > 0) {
                            return 2;
                     }
                     return 3;
              }
       }

它使用float来保存x和y值,尽管它也可以使用double来这样做。float和double都是用于存储浮点数的数值数据类型。double类型需要两倍于float类型的空间,因为每种float类型的数据用 32 位表示,而一种double类型的数据使用 64 位

三元运算符

Java 使您能够直接从布尔表达式中赋值(真或假)。这被称为三元运算符。例如:

       int a, b, max;
       max = a < b? b : a;

这暗示着,当a < b,max = b;否则max = a。

该语法保存一个if / else语句。例如,我们可以使用下面的方法来获得绝对值:

       public int getAbsolutionValue(int a) {
              if (a < 0) {
                     return -a;
              }
              else {
                     Return a;
              }
       }

但是通过使用三元运算符,我们只用一行代码就可以完成:

       a = a < 0 ? -a : a;

问题

  1. 请重写如下代码,以提高其逻辑性和可读性(num为整数值)。

           if (num < 10 && num > 0) {
                  System.out.println("It's an one digit number");
           }
           else if (num < 100 && num > 9) {
                  System.out.println("It's a two digit number");
           }
           else if (num < 1000 && num > 99) {
                  System.out.println("It's a three digit number");
           }
           else if (num < 10000 && num > 999) {
                  System.out.println("It's a four digit number");
           }
           else {
                  System.out.println("The number is not between 1 & 9999");
           }
    
    
  2. Take the following three if statements:

    if (a == 0 && b == 0) {...}
    if (a == 0 && b != 0) {...}
    if (a != 0 && b != 0) {...}
    
    

    请简化代码逻辑,将它们组合在一起。

十九、switch语句

利用switch条件语句代替if语句有时可以呈现更清晰的代码逻辑。当我们有一个变量或一个包含变量的表达式,这些变量可能有不同的结果值,后面跟着不同的动作,这是一个使用switch的好机会。

switch (<expression>) {
       case <result 1>:
              <action 1>;
              break;
       case <result 2>:
              <action 2>;
              break;
       ......
       case <result n>:
              <action n>;
              break;
       default:
              <other action>;
              break;
}

switch 语句的一个简单应用是在x = 1、x = 2或x = 3、……的情况下采取不同的动作,如下所示:

       switch (x) {
              case 1: ...;
              case 2: ...;
              case 3: ...;
              default: ...;
       }

例子

编写一个方法,在给定整数值输入的情况下,用英语单词表达式打印出月份。

回答

我们可以使用if / else梯形语句将一个整数转换成月份名称。

       public static void tellNameOfMonthByIfElse(int month) {
              if (month == 1) {
                     System.out.println("January");
              } else if (month == 2) {
                     System.out.println("February");
              } else if (month == 3) {
                     System.out.println("March");
              } else if (month == 4) {
                     System.out.println("April");
              } else if (month == 5) {
                     System.out.println("May");
              } else if (month == 6) {
                     System.out.println("June");
              } else if (month == 7) {
                     System.out.println("July");
              } else if (month == 8) {
                     System.out.println("August");
              } else if (month == 9) {
                     System.out.println("September");
              } else if (month == 10) {
                     System.out.println("October");
              } else if (month == 11) {
                     System.out.println("November");
              } else if (month == 12) {
                     System.out.println("December");
              } else {
                     System.out.println("Unknown month");
              }
       }

如果我们利用switch条件语句来做同样的翻译,它也会工作得很好。

public static void tellNameOfMonthBySwitch(int month) {
        String nameOfMonth;
        switch (month) {
            case 1:  nameOfMonth = "January";
                     break;
            case 2:  nameOfMonth = "February";
                     break;
            case 3:  nameOfMonth = "March";
                     break;
            case 4:  nameOfMonth = "April";
                     break;
            case 5:  nameOfMonth = "May";
                     break;
            case 6:  nameOfMonth = "June";
                     break;
            case 7:  nameOfMonth = "July";
                     break;
            case 8:  nameOfMonth = "August";
                     break;
            case 9:  nameOfMonth = "September";
                     break;
            case 10: nameOfMonth = "October";
                     break;
            case 11: nameOfMonth = "November";
                     break;
            case 12: nameOfMonth = "December";
                     break;
            default: nameOfMonth = "Unknown month";
                     break;
        }
        System.out.println(nameOfMonth);
}

有一个更好的方法。不如我们定义一个数组来存储用英文表示所有月份的名称字符串列表,也就是数组nameOfMonth。我们实际上是在整数(从 0 到 12)和月份名称字符串之间构建一个映射表。由于数组从索引 0 开始,我们有意将"none"赋给数组中的第一个元素。

       private static String[] nameOfMonth = new String[] {
                     "none", "January", "February", "March", "April", "May", "June",
                     "July", "August", "September", "October", "November", "December"
              };

       public static void main(String[] args) {
              System.out.println(nameOfMonth[1]);    // January
              System.out.println(nameOfMonth[8]);    // August
       }

例子

给定两个整数输入:年和月,编写一个方法来返回一个月中的天数。

回答

使用switch条件语句:

       public static int tellNumberOfDaysByYearMonth(int year, int month) {
              int numOfDays = 0;
              switch (month) {
                   case 1: case 3: case 5:
                   case 7: case 8: case 10:
                   case 12:
                          numOfDays = 31;
                          break;
                   case 4: case 6:
                   case 9: case 11:
                          numOfDays = 30;
                          break;
                   case 2:
                          if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
                                 numOfDays = 29;
                          } else
                                 numOfDays = 28;
                          }
                          break;
                   default:
                          break;
              }
              return numOfDays;
       }

请注意,它有一个特殊的逻辑来处理闰年的二月。由于计算二月份总天数的复杂性,当我们将前面提到的静态数组方法应用于这种情况时,我们必须执行以下操作:

private static int[] numberOfDaysByMonth = new int[] {
                    0,      // none
                    31,     // January
                    28,     // February
                    31,     // March
                    30,     // April
                    31,     // May
                    30,     // June
                    31,     // July
                    31,     // August
                    30,     // September
                    31,     // October
                    30,     // November
                    31      // December
};

在使用整数数组之前,我们需要在运行时根据年份值修改二月的值:

       if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
              numberOfDaysByMonth[2] = 29;
       }

问题

使用 switch 条件语句编写以下代码。

char color ='C';
       if (color=='R') {
              System.out.println("The color is red");
       }
       else if(color=='G') {
       System.out.println("The color is green");
       }
       else if(color=='B') {
              System.out.println("The color is black");
       }
       else {
       System.out.println("Some other color");
       }

二十、追踪移动物体

Java 提供了一个基本的编码框架,比如for或while循环和if或switch条件语句。我们可以利用它们来记录移动物体的时间。首先,我们将处理一个常见的数学问题——弹跳球场景。

数学:弹跳球

在纯数学方法中,我们会建立一个表格来记录每次反弹后的高度。并没有那么难,但是如果我们改变了原始问题设置中的高度值,我们将不得不手动重新计算同一表格中的值。

例子

一个球从 3 米高处落下。在第一次弹跳时,它上升到 2 米的高度。它一直下落,并反弹到上次反弹时达到的 2/3 高度。在哪个弹跳上会上升到不到 0.5 米的高度?这个问题选自过去的 AMC 8(8 年级以下的美国数学竞赛)

回答

这种编程方法将大大减少重复性的手工工作。

       public static void main(String[] args) {
              System.out.println(ballBouncing(3.0));
       }

       private static int ballBouncing(double originalHeight) {
              double currentHeight = originalHeight;
              int count = 0;
              while(currentHeight > 0.5) {
                     currentHeight = currentHeight * 2 / 3;
                     count++;
                     System.out.println("Bounce No=" + count +
                                   "; current height=" + currentHeight);
              }
              return count;
       }

当您执行它时,输出显示每次反弹后的当前高度。

Bounce No=1; current height=2.0
Bounce No=2; current height=1.3333333333333333
Bounce No=3; current height=0.8888888888888888
Bounce No=4; current height=0.5925925925925926
Bounce No=5; current height=0.3950617283950617
5

改变参数originalHeight并重新执行相同的程序会迅速输出详细的结果。这比用传统的数学方法在纸上求解要有效得多。

例子

一只蜗牛试图从井里爬出来。每天它爬上井边 4 英尺,每晚它滑下井 2 英尺 6 英寸。如果蜗牛早上从 40 英尺深的地方开始,它需要多少天才能从井里出来?这个问题选自一个数学竞赛。

回答

为了保持使用整数值,我们通过计算将英尺转换为英寸。注意,我们通过使用关键字final将井的深度设置为一个常量变量。我们在蜗牛每天爬上来之后,滑下去之前,检查它是否到达了井口。

       private static void snail() {
              final int DEPTH = 12 * 40;
              int currentHeight = 0;
              int numOfDays = 0;
              while (currentHeight < DEPTH) {
                     currentHeight += 12 * 4;
                     numOfDays++;
                     if (currentHeight >= DEPTH) {
                            break;
                     }
                     currentHeight -= 12 * 2 + 6;
                     System.out.println("No. " + numOfDays + " day - " +
                                   (DEPTH - currentHeight) + " inches to the top.");
              }
              System.out.println("No. " + numOfDays + " day - at the top.");
       }

这是程序运行时的部分输出:

............

No. 1 day - 462 inches to the top.
No. 2 day - 444 inches to the top.
No. 3 day - 426 inches to the top.
No. 4 day - 408 inches to the top.
No. 5 day - 390 inches to the top.
No. 6 day - 372 inches to the top.
No. 7 day - 354 inches to the top.
No. 8 day - 336 inches to the top.
No. 9 day - 318 inches to the top.
No. 10 day - 300 inches to the top.
No. 11 day - 282 inches to the top.
No. 12 day - 264 inches to the top.
No. 13 day - 246 inches to the top.
No. 14 day - 228 inches to the top.
No. 15 day - 210 inches to the top.
No. 16 day - 192 inches to the top.
No. 17 day - 174 inches to the top.
No. 18 day - 156 inches to the top.
No. 19 day - 138 inches to the top.
No. 20 day - 120 inches to the top.
No. 21 day - 102 inches to the top.
No. 22 day - 84 inches to the top.
No. 23 day - 66 inches to the top.
No. 24 day - 48 inches to the top.
No. 25 day - at the top

.

二十一、计算

我们学习了许多数学方法来解决计数问题。其中有些问题需要对排列组合有深入的理解。在本章中,我们将学习如何使用编程解决计数问题的例子。

例子

公共汽车票价分别为 4 美元和 6 美元。总共卖出了 45 张票,赚了 230 美元。卖出了多少张 4 美元的票?(2007/MathIsCool 问题在 http://academicsarecool.com )

回答

这可以通过单个循环来解决。我们将变量tickets设置为$4.00 门票的数量。因为票的总数是 45,所以$4.00 的票的数量不能大于 45。所以,tickets是 46 以下的整数。

private static void calculateBusTickets() {
       for(int tickets = 0; tickets < 46; tickets++) {
              int totalMoney = 4 * tickets + 6 * (45 - tickets);
              if (totalMoney == 230) {
                     System.out.println(tickets + " $4.00 tickets were sold.");
                     break;
              }
       }
}

例子

椅子有 4 条腿,凳子有 3 条腿,桌子有 1 条腿。生日聚会,每桌 4 把椅子,总共 18 件家具。其中一个孩子数出总共有 60 条腿。有多少凳子?(2016/MathIsCool 问题在 http://academicsarecool.com )

回答

在下面的方法中,变量tables表示表格的数量。那么,椅子的数量是 4 × tables,凳子的数量是(18—tables—4 *tables)。

private static void countFurniture() {
       for(int tables = 0; tables < 19; tables++) {
              if (tables + 4 * 4 * tables + 3 * (18 - tables - 4 * tables) == 60) {
                     System.out.println((18 - tables) + " stools.");
                     break;
              }
       }
}

例子

多项选择题考试由 20 道题组成。每个正确答案的得分为+5,每个错误答案的得分为-2,每个未回答的问题的得分为 0。约翰的考试分数是 48 分。他最多能答对多少个问题?(1987/AMC8 问题在 https://artofproblemsolving.com/wiki/index.php/1987_AJHSME )

回答

与前两个例子不同,在这个例子中,我们将在循环中使用两个变量c和w。假设正确答案的数量是c,错误答案的数量是w。它们的总和不能大于 20,即问题总数。因为它可能有不止一个解,我们不使用break在它找到第一个解后立即退出程序。这是一种不同于前面例子的方法。

private static void scoring() {
       for(int c = 0; c < 20; c++) {
              for(int w = 0; w < 20 - c; w++) {
                     if (5 * c - 2 * w == 48) {
                            System.out.println("Correct answers: " + c
                                          + "; wrong answers: " + w);
                     }
              }
       }
}

输出是:

       Correct answers: 10; wrong answers: 1
       Correct answers: 12; wrong answers: 6

例子

有多少个不同的四位数能被 3 整除,并且最后两位是 23?(2003/10B AMC 问题在 https://artofproblemsolving.com/wiki/index.php/2003_AMC_8 )

回答

我们需要注意这个问题中的措辞,“不同的四位数”。策略是将所有条件分成两部分。

  • 4 位数能被 3 整除,最后两位是“23”。

  • 四位数都不一样。

private static void countNumbers() {
       int totalCount = 0;
       for(int i = 1000; i < 10000; i++) {
              if (i % 3 == 0 && i % 100 == 23) {
                     int firstDigit = i / 1000;
                     int secondDigit = i / 100 % 10;
                     if (firstDigit != secondDigit &&
                            firstDigit != 2 &&
                            firstDigit != 3 &&
                            secondDigit != 2 &&
                            secondDigit != 3) {
                            totalCount++;
                            System.out.println(i);
                     }
              }
       }
       System.out.println("Total count = " + totalCount);
}

它的输出是:

1023
1623
1923
4023
4623
4923
5823
6123
6423
6723
7023
7623
7923
8523
9123
9423
9723
Total count = 17

我们使用一个if子句来验证所有四个数字都是不同的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

或者,我们可以创建一个通用的方法来检查它。

       if (isDistinct(firstDigit, secondDigit, 2, 3)) {
              ......
       }

这是isDistinct(...)的实现。

       private static boolean isDistinct(int a, int b, int c, int d) {
              if (a == b) {
                     return false;
              } else if (a == c) {
                     return false;
              } else if (a == d) {
                     return false;
              } else if (b == c) {
                     return false;
              } else if (b == d) {
                     return false;
              } else if (c == d) {
                     return false;
              } else {
                     return true;
              }
       }

countNumbers2()中的一个改进版本将是:

private static void countNumbers2() {
       int totalCount = 0;
       for(int i = 1000; i < 10000; i++) {
              if (i % 3 == 0 && i % 100 == 23) {
                     int firstDigit = i / 1000;
                     int secondDigit = i / 100 % 10;
                     if (isDistinct(firstDigit, secondDigit, 2, 3)) {
                            totalCount++;
                            System.out.println(i);
                     }
              }
       }
       System.out.println("Total count = " + totalCount);
}

例子

露丝有 10 枚硬币,不是 5 分、10 分就是 25 分。她有 N 个五分镍币、D 个一角硬币和 Q 个二角五分硬币,其中 N、D 和 Q 都不相同,并且都至少是 1。令人惊讶的是,如果她有 Q 个五分镍币、N 个一角硬币和 D 个二角五分硬币,她会有同样多的钱。露丝有多少美分?(2012 年 http://academicsarecool.com 的 MathIsCool 问题)

回答

在以下解决方案中,将使用两个for-回路。

private static void countCoins() {
       for(int n = 1; n < 9; n++) {
              for(int d = 1; d < 10 - n; d++) {
                     int q = 10 - n - d;
                     if (5*n + 10*d + 25*q == 5*q + 10*n + 25*d){
                            System.out.println((5*n+10*d+25*q)+" cents.");
                            System.out.println("N="+n+"; D="+d+"; Q="+q);
                     }
              }
       }
}

输出是:

155 cents.
N=1; D=5; Q=4

例子

三个朋友总共有六支一模一样的铅笔,每个人至少有一支铅笔。这种情况会以多少种方式发生?(2004 年 AMC8 题在 https://artofproblemsolving.com/wiki/index.php/2004_AMC_8 )

回答

我们使用两个for-循环来模拟我们如何将六支相同的铅笔分配给三个人,分别用变量first、second、third来表示。

private static void countWays() {
       int count = 0;
       for(int first=0; first <= 6; first++) {
              for(int second = 0; second <= 6 - first; second++) {
                     int third = 6 - first - second;
                     if (first > 0 && second > 0 && third > 0) {
                            count++;
                                   System.out.println("first=" + first + "; second=" + second + "; third=" + third);                     }
              }
       }
       System.out.println("Total count=" + count);
}

输出是:

first=1; second=1; third=4
first=1; second=2; third=3
first=1; second=3; third=2
first=1; second=4; third=1
first=2; second=1; third=3
first=2; second=2; third=2
first=2; second=3; third=1
first=3; second=1; third=2
first=3; second=2; third=1
first=4; second=1; third=1
Total count=10

例子

七块不同的糖果被分在三个袋子里。红色的袋子和蓝色的袋子必须每人收到至少一块糖果;白色袋子可以保持为空的。有多少种可能的安排?(2010/10B AMC 问题在 https://artofproblemsolving.com/wiki/index.php/2010_AMC_10B )

回答

首先,我们设计一个实验。在这个实验中,我们希望将七个不同的字符串(“A”、“B”、“C”、“D”、“E”、“F”、“G”)放入三个字符串数组中。这七根线代表七种不同的糖果。这三个数组分别代表红色、蓝色和白色的袋子。放置的顺序并不重要,但是我们需要确保在放置完成后只有最后一个数组可以为空。目标是找到不同位置的数量。

当我们将“A”放入三个数组中的一个时,我们需要一个 for 循环来处理三个不同的数组。然后我们需要另一个for-循环来放置“B”,以此类推;我们总共需要七个 for 循环。在每个for-循环中,我们将字符串追加到现有数组中,即bag[i]。但是完成之后,我们需要将它从数组字符串的尾部移除,以便它尝试下一个选项。这就是我们使用bag[i].replace("A", "")的原因。这同样适用于其他六根弦。

我们想出了一个“直截了当”但看起来很丑的版本,如下所示。

注意

包–红色:0,蓝色:1,白色:2;循环中的 3 代表三个字符串数组,即三个袋子。

/// BAG - red: 0, blue: 1, white: 2
private static void distributeCandy() {
    int count = 0;
    String[] bag = { "", "", "" };
    for(int i=0; i < 3; i++) {
        bag[i] += "A";
        for(int j=0; j < 3; j++) {
            bag[j] += "B";
            for(int k=0; k < 3; k++) {
                bag[k] += "C";
                for(int l=0; l < 3; l++) {
                    bag[l] += "D";
        for(int m=0; m < 3; m++) {
            bag[m] += "E";
            for(int n=0; n < 3; n++) {
                bag[n] += "F";
                for(int p=0; p < 3; p++) {
                    bag[p] += "G";
                    if(bag[0].length() > 0 && bag[1].length() > 0) {
                                  count++;
                        System.out.println("Red=" + bag[0] + " Blue=" + bag[1] + " White=" + bag[2]);
                    }
                    bag[p] = bag[p].replace("G", "");    }
             bag[n] = bag[n].replace("F", "");   }
        bag[m] = bag[m].replace("E", "");    }
                bag[l] = bag[l].replace("D", "");    }
            bag[k] = bag[k].replace("C", "");    }
        bag[j] = bag[j].replace("B", "");   }
    bag[i] = bag[i].replace("A", "");    }
    System.out.println("Total count: " + count);
}

代码结构看起来太复杂了。嵌套的for-循环太多。一个更好的想法是应用递归方法来提高它的简单性。现在看新版本:

private static int count = 0;
private static String[] bag = { "", "", "" };
private static String[] CANDY = new String[] { "A", "B", "C", "D", "E", "F", "G" };
private static String RemoveLastChar(String s) {
       if (s == null && s.length() < 1) {
              System.out.println("Input string is invalid!");
              return "";
       }
       return s.substring(0, s.length() - 1);
}
private static void distributeCandies_Recursive(int pointer) {
       for(int i=0; i < 3; i++) {
              bag[i] += CANDY[pointer];
              if (pointer == CANDY.length - 1) {
                     if (bag[0].length() > 0 && bag[1].length() > 0) {
                            count++;
                            System.out.println("Red=" + bag[0] + " Blue=" + bag[1] + " White=" + bag[2]);
                     }
              }
              else {
                     distributeCandies_Recursive((pointer + 1));
              }
              bag[i] = RemoveLastChar(bag[i]);
       }
}

然后,我们在执行的main函数中包含下面两行。

distributeCandies_Recursive(0);
System.out.println("Total count: " + count);

例子

随机选择 1000 到 10000 之间的回文。被 7 整除的概率是多少?(2010/10B AMC 问题在 https://artofproblemsolving.com/wiki/index.php/2010_AMC_10B )

回答

回文数字是一个从左到右和从右到左读起来一样的数字。

在isPalindrome()方法中,我们反转数字串,并与原始数字串进行比较。如果反转后的字符串与原来的字符串相同,则被识别为回文字符串。" 8558 "它的反串“8558”和它自己是一样的。

我们引入StringBuffer类来利用它的reverse()方法。范围[1000,10000]内的每个数字在被传递给isPalindrome()方法之前都被转换为字符串类型。该解决方案可以应用于任何范围的整数。

public static void main(String[] args) {
       countDivisibility();
}

private static boolean isPalindrome(String numberStr) {
       String reversed = new StringBuffer(numberStr).reverse().toString();
       return reversed.equals(numberStr);
}

private static void countDivisibility() {
       int count = 0;
       int total = 0;
       for(int i = 1000; i < 10001; i++) {
              if(isPalindrome(Integer.toString(i))) {
                     total++;
                     if (i % 7 == 0) {
                            count++;
                            System.out.println(i);
                     }
              }
       }
       System.out.println("Probability=" + count + "/" + total);
}

方法isPalindrome2()中有一种不同的方式,它包含与isPalindrome()方法相同的功能。除了使用StringBuffer,你可以简单地比较每个字符的前半部分和后半部分。

private static boolean isPalindrome2(String s) {
       int len = s.length();
       for( int i = 0; i < len / 2; i++ ) {
                     if (s.charAt(i) != s.charAt(len - i - 1)) {
                                    return false;
                     }
       }
       return true;
}

例子

随机选择一个以 10 为基数的三位数 n。n 的 9 进制表示和 11 进制表示都是三位数的概率是多少?(2003/10A AMC 问题在 https://artofproblemsolving.com/wiki/index.php/2003_AMC_10A_Problems )

回答

十进制三位数的总数是 900。十进制的三位数 124 是九进制的 147,十一进制的 103;10 进制 720,9 进制 880,11 进制 5A5。

关键的方法是countBase10Numbers():

private static void countBase10Numbers() {
       int count = 0;
       for(int i = 100; i < 1000; i++) {
              String base9Number = convertToBaseN(i, 9);
              String base11Number = convertToBaseN(i, 11);
              if (base9Number.length() == 3 &&
                     base11Number.length() == 3) {
                     count++;
                     System.out.println(i + " -> " + base9Number +
                                   "; " + base11Number);
              }
       }
       System.out.println(count + " out of " + (1000 - 100));
}

支撑方式是convertToBaseN()。

private static String convertToBaseN(int base10, int n) {
       if(n < 2 || n > 16) {
              return "";
       }
       String baseN = myOneDigit[base10 % n];
       base10 = base10 / n;
       while(base10 > 0) {
              baseN = myOneDigit[base10 % n] + baseN;
              base10 = base10 / n;
       }
       return baseN;
}

myOneDigit数组是:

private static String[] myOneDigit =
{ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" };

它实际上相当于一个实现了switch条件语句的方法:

private static String convertDigit(int digit) {
       String s = "";
       switch(digit) {
              case 10:
                     s = "A";
                     break;
              case 11:
                     s = "B";
                     break;
              case 12:
                     s = "C";
                     break;
              case 13:
                     s = "D";
                     break;
              case 14:
                     s = "E";
                     break;
              case 15:
                     s = "F";
                     break;
              default:
                     s = Integer.toString(digit);
                     break;
       }
       return s;
}

显然,使用字符串数组的方法更简单。

问题

  1. Richa 和 Yashvi 将和他们的学校一起去牙买加。他们计划参加一个儿童门票 1.5 美元、成人门票 4 美元的博览会。在特定的一天,2200 人进入交易会,并收取 5050 美元。有多少孩子参加了?(2017 MathIsCool)

  2. 在一次有 10 道题的数学竞赛中,一个学生答对一题得 5 分,答错一题得 2 分。如果奥利维亚回答了所有问题,她的分数是 29,那么她有多少个正确答案?(2002 年 AMC8)

  3. 有多少不超过 2001 的正整数是 3 或 4 的倍数而不是 5 的倍数?(2001 年 AMC10)

  4. 有多少个三位数的正数恰好包含两个不同的数字(例如,343 或 772,而不是 589 或 111)?(2006 MathIsCool)

  5. 丽贝卡去商店买了五株植物。如果商店出售三种类型的植物,她可以购买多少种不同的植物组合?(2005 MathIsCool)

二十二、因式分解

在学校数学中,我们通常遵循一个程序来寻找任何给定正整数的所有因子。这个过程叫做因式分解,根据整数有多大,需要相当多的计算。使用 Java 编程环境,让我们创建一个简单的程序来为我们做同样的工作。我们想写代码来找出任意正整数的所有因子。当用户输入“10”时,程序应该输出:1、2、5 和 10。作为第一步,我们需要定义过程,然后用 Java 代码实现它。

数学:寻找因子

回想一下我们在学校是如何手动寻找因子的,我们用一个整数从最小的(即“1”)到最大的(即给定的整数本身),一个一个地,来检查它是否能被给定的数整除。当答案是肯定的时候,我们知道这是一个因素。否则,我们跳过它,转到下一个数字。

我们创建下面的代码块来完成这个过程。我们将这个版本的代码标记为“v1”,并计划从这里进行改进。

private static int listFactors_v1(int n) {
       int counter = 0;
       for (int i = 1; i <= n; i++) {
              if (n % i == 0) {
                     if (counter > 0) {
                            System.out.print(", ");
                     }
                     System.out.print(i);
                     counter++;
              }
       }
       System.out.println();
       System.out.println("Number of factors: " + counter);
       return counter;
}

main方法将如下所示:

public static void main(String[] args) {
       Scanner input = new Scanner(System.in);
       int iterations = 0;
       while (true) {
              iterations++;
              System.out.println("Enter an integer number:");
              int k = input.nextInt();
              if (k < 0) {
                     k = -k;
              }
       }

       System.out.println("Number of factors: " + listFactors_v1(k));
       input.close();
}

当您编译并执行代码时,您将看到如下输出:

Enter an integer number:
2018
1, 2, 1009, 2018
Number of factors: 4

不要认为我们有解决这个问题的完美方案。实际上,它远未完成。

数学:将问题减半

当我们迭代从 1 到 n 的每一个单个数字时,为了找到 n 的所有可能的除数,我们观察到任何大于 n/2 的整数都不会是 n 的除数,因此,我们只需要检查从 1 到 n/2,而不是 n,这个变化将节省程序中一半的迭代次数。因此,我们现在在下面的 2.1 版本中有了直接的改进。

private static int listFactors_v21(int n) {
       int counter = 0;
       for (int i = 1; i <= n / 2; i++) {
              if (n % i == 0) {
                     if (counter > 0) {
                            System.out.print(", ");
                     }
                     System.out.print(i);
                     counter++;
              }
       }
       System.out.println(", " + n);
       counter++;
       System.out.println("Number of factors: " + counter);
       return counter;
}

除了算法的改变,我们还将删除一个if子句,以稍微降低复杂性。然后我们会拿出下面的 2.2 版本,稍加修改。

private static int listFactors_v22(int n) {
       System.out.print("1"); // "1" is always the 1st factor
       int counter = 1;
       for (int i = 2; i <= n / 2; i++) {
              if (n % i == 0) {
                     System.out.print(", " + i);
                     counter++;
              }
       }
       System.out.println(", " + n); // n is always the last factor
       counter++;
       System.out.println("Number of factors: " + counter);
       return counter;
}

够好吗?其实不是。

数学:使用平方根

如果我们记得在数学中如何测试正整数是否为质数,我们只使用从 2,3 到 n 的平方根的整数。我们将在这里应用相同的逻辑来寻找一对因子,以减少迭代次数。

private static int listFactors_v31(int n) {
       int counter = 0;
       for (int i = 1; i <= Math.sqrt(n); i++) {
              if (n % i == 0) {
                     if (counter > 0) {
                            System.out.print(", ");
                     }
                     System.out.print(i);
                     counter++;
                     if (i != n / i) {
                            System.out.print(", " + n / i);
                            counter++;
                     }
              }
       }
       System.out.println();
       System.out.println("Number of factors: " + counter);
       return counter;
}

目前的 3.1 版本显然更好,因为它只检查 n 的平方根,而不是 n/2。以 n=100 为例,现在我们从 1 到 10 进行检查,而不是从 1 到 50。显然,迭代次数的减少是显著的。但是我们很快发现了一个问题。当前解决方案的输出是:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因子列表并不像我们希望的那样按升序排列,只是因为它成对地打印出因子。为了解决这个问题,我们将创建两个字符串。一个字符串存储每对因子中较小的一个。另一个字符串存储每对中较大的一个。

private static int listFactors_v32(int n) {
       String s1 = "1";
       String s2 = Integer.toString(n);
       int counter = 2;
       for (int i = 2; i <= Math.sqrt(n); i++) {
              if (n % i == 0) {
                     s1 += ", " + i;
                     counter++;
                     if (i != n / i) {
                            s2 = n / i + ", " + s2;
                            counter++;
                     }
              }
       }
       System.out.println(s1 + ", " + s2);
       System.out.println("Number of factors: " + counter);
       return counter;
}

我们能从目前的 3.2 版本中做进一步的改进吗?答案还是肯定的。我们没有将每对除数中较小的数存储到字符串中,而是直接将其发送到控制台。这将节省一个字符串的内存空间。这是另一个“小”的变化,但当我们处理一个可能包含大量因素的大数字时,这可能是一个巨大的节省。我们最终登陆了 3.3 版:

private static int listFactors_v33(int n) {
       String s = Integer.toString(n);
       int counter = 2;
       System.out.print("1");
       for (int i = 2; i <= Math.sqrt(n); i++) {
              if (n % i == 0) {
                     System.out.print(", " + i);
                     counter++;
                     if (i != n / i) {
                            s = n / i + ", " + s;
                            counter++;
                     }
              }
       }
       System.out.println(", " + s);
       System.out.println("Number of factors: " + counter);
       return counter;
}

以下是我们为解决这一问题所做工作的总结:

  • 我们将整数的实际上限从 n 减少到 n/2,然后减少到 n 的平方根。

  • 我们避免了使用额外的字符串进行临时存储。

  • 我们一直在思考如何根据三个基本规则来改进我们的实现:

    1. 采用我们所知的最佳算法;

    2. 优化代码,消耗更少的内存,运行更快;

    3. 编写易于理解的代码,以便将来维护。

所有这些努力都促成了一个优化良好的代码。这的确是编程的艺术。

二十三、PI 的探索性实验

为了监测自然环境变化对鱼类生命周期的影响,科学家们必须一直跟踪鱼类的数量。一个湖里有一种叫 AA 的鱼供研究。科学家们将一小群标记为 AA 的鱼放归湖中,它们的总数等于#(total _ labelled)。一段时间后,他们从湖中随机捕获一些鱼 AA 作为样本,其总数等于#(total_captured)。在这些样本鱼 AA 中,他们整理出标签鱼 AA,其总数等于#(labelled _ inter _ captured)。

数学:计算人口

假设所有的鱼,包括标记的和未标记的,均匀地分布在湖中,我们使用下面的公式计算出湖中鱼 AA 的当前数量。

 #(total_captured) * #(total_labeled) / #(labeled_among_captured)

该公式以简单的比率形式表示。湖中分布越均匀的鱼 AA,公式产生的结果就越准确。它本质上是一种统计思想,使用少量样本数据来预测大图中可能很大的总数。它试图以最小的误差对不可测量的物体进行测量。

鱼类实验的本质是基于概率论。它也适用于许多其他有趣的问题领域。其中之一是计算圆周率:3.14159…

例子

怎么做基本编程才能算出圆周率的值?

数学:概率论中的圆周率

我们将一个圆内接成一个正方形,在笛卡尔坐标平面中紧靠 x 轴和 y 轴。假设正方形的长度(即圆的直径)为 n,圆的面积可以用公式表示为:

  • p × (n/2) 2

p 是要搞清楚的东西,就是圆周率。

如果在正方形内随机选择一个点,该点正好在圆内的概率是多少?

学过基本的几何概率就知道答案了。应该是圆和正方形的面积比。由于正方形的面积是 n 2 ,所以比例会是 p/4。

  • p×(n/2)2:n2= p:4

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

回答

概率 p/4 表明,如果我们尽可能多地重复相同的点选择过程,圆内选择的点数与正方形内选择的点数之比将接近(并最终等于)p/4。因此,一旦我们找出比率,我们就知道圆周率的近似值。这是我们将在程序中使用的算法。

public static double computePi(int total, int n) {
       int count = 0;
       for(int i=0; i < total; i++) {
              double x = n * Math.random();
              double y = n * Math.random();
              if ((x - n/2) * (x - n/2) + (y - n/2) * (y - n/2)
                            < (n/2) * (n/2)) {
                     count++;
              }
       }
       return (double)count * 4 / total;
}

在这种方法中,

  • 整数参数值total是实验的总数(即所选样本点的总数)。

  • 整数参数值n是正方形的边长,或者圆的直径。

  • Math.random()是来自java.util.Random包的 Java 内置函数。它生成一个介于 0 和 1 之间的双精度随机数。乘以n使 x 和 y 坐标值在 0 和n之间。

  • 不等式“(x-n/2)2+(y-n/2)2<(n/2)2”是检查该点是否位于圆心在(n/2,n/2)的圆内。

    您可以通过跟随main方法()中的行来调用该方法

    :

    public static void main(String[] args) {
           int onehMillion = 100 * 1000 * 1000;
           for(int i=0; i < 10; i++) {
                  System.out.println(computePi(onehMillion, 100));
           }
    }
    
    
  • n = 100是边长。它不会直接影响公式。您可以使用其他数字,如 10 或 2 或任何偶数(由于“n/2”),用于扩展实验目的。

  • int onehMillion = 100 * 1000 * 1000等于 1 亿。它表示我们在一次探索性测试中选取的总点数。100 * 1000 * 1000是一个乘法操作,将在编译期间运行之前执行。当前的乘法表达式在编码中不存在额外的计算时间。

  • for -loop ()多次驱动相同的实验,即 10 次。

控制台上的输出如下所示:

3.14150492
3.14166436
3.14157872
3.14143904
3.14174756
3.14153872
3.14161072
3.14155196
3.14198448
3.14158056

该方法使用不到 10 行代码,完成执行并输出估计的 Pi 值大约需要 5 秒钟。

最后但同样重要的是,如果total和i的值太大,我们需要将int改为long。记住int类型的数据最大可达 32 位,相当于 2 32 。当总数大于这个数时,我们将需要使用long类型,它支持 64 位(等于 2 64 )。

public static double computePi(long total, int n) {
       long count = 0;
       for(long i=0; i < total; i++) {
              double x = n * Math.random();
              double y = n * Math.random();
              if ((x - n/2) * (x - n/2) + (y - n/2) * (y - n/2)
                            < (n/2) * (n/2)) {
                     count++;
              }
       }
       return (double)count * 4 / total;
}

参数的长值类型需要作为...L传递,如下所示。然而,这将需要更长的时间来执行,除非它运行在一个高计算能力的 PC 上。

public static void main(String[] args) {
       long hugeNumber = 1000 * 1000 * 1000 * 1000L;
       for(int i=0; i < 10; i++) {
              System.out.println(computePi(hugeNumber, 100));
       }
}

如果我们增加total的值,它将通过更多的点覆盖更多的区域,并返回更精确的圆周率结果。对于我们在这个程序中选择的 1 亿个点,它几乎保证找出 Pi = 3.141…,精确到千分之一。为了达到更高的精度,我们需要一台更强大的计算机。至少我们知道,有了理想的计算平台,我们将能够在指定的精度水平上确定圆周率值。

从这个例子中,我们了解到,只要我们知道曲线的函数模型,我们可以应用相同的比率和概率概念来找出由任何曲线包围的区域。

例子

牢记概率概念,用 Java 编程求直线 x = 0,y = 0,曲线 y = -2x 2 + 12x -18 之间的面积。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

回答

这种方法已经帮助我们解决了一个问题,而一个纯数学的解决方案原本需要微积分的知识。

       public static double computeArea(int total) {
              int count = 0;
              for(int i=0; i < total; i++) {
                     double x = Math.random() * 3;
                     double y = Math.random() * -18;
                     if (-2 * x * x + 12 * x - 18 < y) {
                            count++;
                     }
              }
              return (double)count * 54 / total;
       }

问题

创建一个程序,找出欧拉数 e。

Android实战项目论文 - 趣味数学 专注于Android/Unity和各种游戏开发技巧,以及各种资源分享(网站、工具、素材、源码、游戏等) 阅读详情

相关推荐

ClearML中文文档实战:从安装到第一个实验的保姆级教程

本文提供ClearML从零开始的实战指南,涵盖核心组件理解、Python SDK安装、服务器配置及首个自动化实验的完整流程。通过改造PyTorch训练脚本的实例,详细演示了如何利用ClearML自动记录实验参数、指标与模型,实现机器学习实验的可复现性与高效管理,并简要介绍了进阶的自动化工作流。

weixin_29216049的博客 398

HTML5 游戏开发示例(一)

HTML5 承诺将成为在线游戏的热门新平台。HTML5 游戏在电脑、智能手机、平板电脑、iPhone 和 iPad 上运行。成为今天最早开发 HTML5 游戏的开发者之一,并为明天做好准备!本书将向您展示如何使用最新的 HTML5 和 CSS3 网络标准来构建卡牌游戏、绘图游戏、物理游戏,甚至是网络多人游戏。有了这本书,您将通过清晰的系统教程构建六个示例游戏。HTML5、CSS3 和相关 JavaScript API 是 Web 的最新热门话题。这些标准为我们带来了新的 HTML5 游戏市场。借助它们的新力

龙哥盟 1765

期货分仓系统CTP协议/国内期货软件源码

期货分仓系统与CTP协议以及国内期货软件源码是期货交易技术领域的几个重要方面。

q2247238820的博客 962

C#游戏编程之创建一个简单的卷轴射击游戏

前几天很多朋友要求贴一篇有关C#游戏开发的实例。本篇文章是创建一个简单的卷轴射击游戏开发实例,内容比较完整,分享给大家,不过篇幅有些长,可以慢慢看哈!本文除优快云博客外,任何媒体和出版物禁止转载和使用。 下面将介绍如何开发一个简单的游戏,首先设计一个基本的计划,然后展示其实现过程。实现将以实效的迭代方式完成。高层次的第一遍开发将使游戏结构可以工作,然后优化这个结构,直到它接近对游戏的最初描述。

清图出版 4万+

Jupyter Notebook 命名出现“error”且运行后没反应

Jupyter Notebook 命名出现“error”且运行后没反应提前声明错误截图(方便大家看看是不是自己的错误)解决方法 提前声明 我的问题是在看到答主 @开始King的回答后才解决的,因为答主大大的文章后面有些地方不是很详细,我在这里再在King大大的基础上完善一下子 错误截图(方便大家看看是不是自己的错误) 1.命名失败,上面出现一个“error”字样 2.运行失败,无论是点击上方的运行按钮还是按快捷键shift+enter 都只会向下再增加一个代码块,而不会运行程序。 (也不是很多人出现的[*

qq_52770743的博客 1万+

HFSS新手避坑指南:手把手教你用FR4基板仿真威尔金森功分器(附参数优化技巧)

本文详细介绍了使用HFSS仿真FR4基板威尔金森功分器的12个关键细节,包括介质基板设置、微带线建模、隔离电阻设置等实战技巧。特别针对微波技术中的常见问题,提供了参数优化和结果解读的实用方法,帮助新手快速掌握HFSS仿真技能。

weixin_27310417的博客 226

井字棋小游戏代码(Visual Studio)

#include<graphics.h> #include<conio.h> #include<iostream> #include "EasyXPng.h" #define W 500 #define H 600 using namespace std; //一些全局变量 MOUSEMSG m; // 定义鼠标消息 IMAGE hand; //鼠标图案 int k = 0; //控制一步一棋子//k = 0,a; // k = 1,b; int m...

有朋自远方来,不亦乐乎。 2786

深入YOLOv8内部核心:用RepNCSPELAN4深度重构主干网络,即插即用的高效涨点方案

本文提出了一种改进YOLOv8目标检测模型的方法,通过在YOLOv8中引入RepNCSPELAN模块来提高检测性能。该模块融合了RepVGG重参数化思想与CSP-ELAN结构,在保持推理速度的同时增强特征表达能力。实验结果表明,改进后的RepNCSPELAN-YOLOv8相比原模型在多项指标上均有提升:准确率从0.84提高到0.86,召回率从0.72提升至0.81,mAP50和mAP50-95也分别提高了0.06和0.04。文章详细介绍了模块设计原理和移植步骤,包括配置文件创建、代码修改等关键环节,为YOL

FJN110的博客 187

java5游戏编程_JAVA实现游戏编程(5)

/**ClientControl.java**Createdon2007年10月2日,下午2:02*此类是客户端中的关键类,此类专门负责整个程序的*流程和表现,负责对外通讯*Tochangethistemplate,chooseTools|TemplateManager*andopenthetemplateintheeditor.*/packageco...

weixin_30802399的博客 454

eCognition易康操作教程(一):如何利用eCognition易康软件进行影像分割之棋盘分割、四叉树分割、光谱差异分割

进程执行完成后,植被覆盖区域与裸地区域合并了。第三步:清除分割结果,点击“Image Objects”菜单栏,点击“Delete Level(s)”,选中“ResultLevel1”,点击”ok”删除棋盘分割结果。四叉树分割之后,有的正方形大一些,有的正方形小一些,大说明该区域的光谱特性更加均一,而小说明不太均一。Leve:选择运行算法的矢量层名称,这里选择四叉树分割算法得到的矢量层“ResultLevel2”。Image Layer weights:图层权重,这里设置为“1,1,1,1”。

蒹葭苍苍 4608

OceanBase备租户创建(二):通过BACKUP DATABASE PLUS ARCHIVELOG

OceanBase数据库备租户创建方法二:通过BACKUP DATABASE PLUS ARCHIVELOG功能实现,特别适用于社区版和单机版部署模式。

Sebastien23的博客 542

Java 数学学习手册(一)

市场上有很多好的 Java 编程书籍,但是对于一个刚接触 Java 并且只有很少编程知识的初学者来说,找到一本合适的并不容易。这本书将帮助初学者学习如何有效地用 Java 编程。我的意图是简化 Java 更复杂的方面,并指导学习者探索“幕后”的东西我希望这本书里面的说明足够直观,读者可以通过实践来理解。有编程经验的人都明白,数学知识在程序设计中起着至关重要的作用。所以拥有良好的数学功底在学习编程的时候无疑是超级有帮助的。这本书提供了一个在编程环境中练习数学问题解决的好机会。

龙哥盟 1199

解锁激光加工密码:功率、频率、脉宽、占空比全解析

激光加工利用高能量激光束实现材料加工,具有无接触、高效率等特点。其核心参数包括功率(决定能量输出)、频率(控制脉冲重复)、脉宽(调节能量作用时间)和占空比(调控工作周期),这些参数相互协同影响加工效果。针对不同材料需采用差异化参数组合:金属材料需较高功率,塑料需低功率防过热,陶瓷需高频短脉宽减少热应力。实际操作中应通过小范围测试逐步优化参数,并注意解决烧损、切割不平整等常见问题。合理调节这些参数可实现高质量、高效率的激光加工。

远程部署调试 运行安装 项目调试 二次开发 项目技术新 持续迭代 部分源码免费分享 616

Java 数学学习手册(三)

原文:Learn Java with Math 协议:CC BY-NC-SA 4.0 二十四、面向对象编程中的类 一个对象本质上是一个事物的表示。一个物体有一些属性,就像任何事物都有特性一样。然而,编程世界中的类主要是为特定对象设计的数据结构。这个类也被认为是一个对象的蓝图。它跟踪关于该对象的一系列相关事物。这些相关的东西被称为字段、属性和函数(或方法)。 字段是类的数据成员。在使用它们之前,必须声明和初始化它们。它们主要供班级内部使用。 一些字段可以充当属性,即对象的属性(例如,雇员的姓名或银行账户的

龙哥盟 883

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Java计算机毕业设计小学生在线数学学习平台(开题报告+源码+论文)

通过该平台的运用,期望能够:1) 增强学生的自主学习能力,激发其对数学的兴趣与热爱;其次,通过个性化学习路径的推荐和实时学习数据的分析,平台能够帮助每位学生找到最适合自己的学习节奏和方法,促进学习效率与质量的双重提升。此外,该平台还为教师提供了强大的教学辅助工具,便于教师精准掌握学生的学习状况,及时调整教学策略,实现教学相长。该平台旨在通过整合丰富的视频教学资源、实时学习反馈、智能化作业管理系统等功能,为小学生提供一个随时随地、因材施教的数学学习环境,以激发学习兴趣,提升学习效果。

茹茹学姐 1202

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

《DeepSeek中小学生使用手册》帮助家长和老师全方位解决孩子学习,成长20大痛点问题!!

手册详细介绍了DeepSeek这一人工智能学习助手如何帮助中小学生提升阅读能力、英语学习、数学学习以及成为孩子的成长顾问。文档内容涵盖了学习方法、时间管理、情绪调节、选科与专业选择、生涯规划、亲子关系、社交能力、升学压力、学习方法和心理健康等多个方面。通过具体的使用原则、实例和分析,手册旨在为中小学生和家长提供一个全面的学习和成长指导。能够从小都在AI的加持下,辅助中小学生的教育,成长,这对于学校,老师,和家长而言,都是一大利器。不得不说,对于中小学生和他们的家长而言,这份教程真的非常及时。

xuxinyang100的专栏 624

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

学java要数学好吗-java程序员数学不好怎么办?,华为普工面试经验

1.JVM:JVM 是初级Java 程序员成长路上的一道必经之路,学习JVM之前,只需要知道代码编译成 Class,虚拟机加载 Class 运行就可以了,学习 JVM 之后,可以深入理解代码从编译到加载的过程、内存中对象的创建与垃圾回收、日常开发中快速定位性能问题等,当然也是面试不可缺少的加分项。2.Java集合:

2401_84447390的博客 536

想入行 AI,怎么选择有效的技术培训

IT 行业发展迅速,各种新名词此起彼伏。近几年的大数据、人工智能、机器学习等等各种概念满天飞。只要是从业人员,好像不学点模型算法 DNN 都对不起自己程序员的身份了,更何况这些名词背后的职位往往意味着令人心动的薪水。 学习是必须的,可是怎么学呢?从头看书太辛苦了,网上的文章又太碎片化,是不是报一个培训班,交点钱听人讲更容易学会?培训班有那么多,这个是证书,那个是优惠,再一个给提供工作机会,到底选那...

GitChat 1456

2018的1/6已经过了,你的新年计划实现的如何了呢?

    回首上个月的计划,感觉还是计划赶不上变化,总体来讲还是做了不少。    先总结上个月的计划,首先是书。《腾讯Android自动化测试》一书二十五号才邮寄过来,可能是因为我贪图小便宜了。然后这个月没有达成上个月的目标,知识粗略地看了前第五章。这本书其实还蛮不错的(教材)。很多东西都是把官方资料or官方源码直接copy上去,然后写一些自己使用的经验以及对源码的总结。这些东西确实对我们这些小白的...

正心全栈编程 272

我的世界 java开发者_GitHub - Cat7373/MinecraftDeveloperGuide: Minecraft developer Chinese guide,我的世界开发者中文指南...

我的世界开发者中文指南目录新手的疑问初学者都有很多疑问,在这里对这些疑问进行一一解答。我英语不好,可以学习编程吗?对于初学者来说,英语不是主要的障碍,国内有着充足的中文教程。但在接下来的学习过程中,需要阅读大量的英文文档,所以还是需要有一些英语基础和理解学习能力,配合翻译工具(如百度翻译)进行理解。我数学不好,可以学习编程吗?对于初学者来说,有必要掌握数学逻辑思维和解决问题的思路,这些能力都在数学...

weixin_31327207的博客 641

JSP考研数学在线解答系统x8dot(程序+源码+数据库+调试部署+开发环境)

随着考研热度的逐年攀升,数学作为考研的重要科目,其复习难度和重要性日益凸显。传统的复习方式往往依赖于纸质资料和面授辅导,但这种方式存在资料更新慢、答疑不及时等问题。因此,开发一款考研数学在线解答系统,旨在通过互联网技术为考生提供便捷、高效的数学学习平台,具有重要的现实意义和应用价值。

CK3011的博客 922

深入十的科学世界探索学习工程师的奥秘与价值解析未来之路

在当今数字化和工业4.0的时代,工程师已成为推动社会进步的核心力量。《10的科学:为什么学习会工程师》一书,由知名教育学家李明博士撰写,于2023年出版,迅速成为STEM教育领域的畅销作品。这本书以“10的科学”为隐喻,象征学习过程的十项核心原则——包括系统性、创新性、实践性等——并深入剖析了为什么这些学习原则能有效培养出卓越的工程师。李明博士结合认知心理学和工程案例,论证了学习不仅是知识积累,更是思维模式的塑造。例如,书中引用了硅谷工程师的真实故事,展示他们如何通过持续学习克服技术挑战。

2509_93935300的博客 1371

基础数学与算法学习

基础算法: 数据结构与算法分析:C语言描述 程序员代码面试指南——IT名企算法与数据结构题目最优解 算法设计与分析基础 (Ananny Levitin著) 算法(Robert著 第四版) 编程原本 算法导论 算法技术手册 算法设计(王红梅编著 一本学校教材) 零散网络流传的文档 基础数学: 概率论与数理统计 离散数学及其应用 统计学的世界 统计学完全教程 线性代数及其应用 线性代数应该这样...

weixin_34342992的博客 207

哈佛级文书打磨系统:AI作为思维镜像师的三阶介入模型

文书写作本质是认知成长的外化过程,其核心在于思想密度、叙事张力与自我认知深度——这三大指标无法由AI生成,却可被AI精准诊断与结构化淬炼。基于哈佛招生实践与NLP语义分析,本文提出‘诊断—淬炼—压力测试’三阶模型,将AI定位为‘思维显微镜’与‘证据审计员’:通过思想密度热力图识别具象锚点缺失,用靶向改写方案激发感官沉浸与时间锚点重构,并以招生官质疑矩阵驱动跨材料证据链闭环。该方法不替代人类反思,而是把模糊的‘写得好不好’转化为可测量、可追溯、可证伪的认知行动项,真正服务于17岁青少年在关键成长节点上的真实表

weixin_34192816的博客 431

数据科学数学实战指南:四层嵌套结构与够用阈值

数据科学中的数学不是抽象理论,而是支撑问题求解、工具调用与模型调试的底层接口。从概率论的条件概率与贝叶斯更新,到统计学的假设检验与置信区间,从线性代数的特征向量与SVD降维,再到微积分的梯度概念与优化直觉——这些基础模块共同构成‘数学-问题-代码’的直觉映射链。其核心价值在于控制不确定性、识别偏差、解释黑箱并适配业务逻辑,广泛应用于AB测试归因、用户分群验证、特征工程设计、模型可解释性分析及线上漂移监控等真实场景。本文聚焦‘够用阈值’与‘嵌套分层’,拒绝教科书式灌输,直击数据工程师每日面对的数学接口选择与误

weixin_30698527的博客 478

InnoDB 内存结构总览:Change Buffer、AHI 与 Log Buffer

本文系统梳理InnoDB内存结构中的ChangeBuffer、Adaptive Hash Index(AHI)与LogBuffer。ChangeBuffer缓存二级索引页不在内存时的变更,减少随机IO,仅在页加载时合并;聚簇索引修改立即执行,因数据本身不可延后。AHI基于高频等值查询自动构建哈希索引,加速定位,仅支持等值操作。LogBuffer为redo log内存缓冲,配合磁盘日志实现崩溃恢复。三者均服务于性能优化,其中ChangeBuffer与AHI共享BufferPool空间,而LogBuffer独立

bksczm的博客 289
上一篇: Java 数学学习手册(三)
下一篇: Java 机器人编程入门手册(一)
绝不原创的飞龙
绝不原创的飞龙 优质创作者: 人工智能、数据科学与机器学习技术领域 优质创作者: 人工智能、数据科学与机器学习技术领域
博客等级 码龄15年 4万+粉丝 2万+原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值