以正弦波形式打印数字

10

背景:

我已经成功编写了可以生成从0到2pi的正弦波的代码。通过调整常量xPrecisionyPrecision,您可以在水平或垂直方向上拉伸图形。

xPrecision = yPrecision = 10 时,我获得了这个漂亮的输出(在Eclipse中):

enter image description here

我的问题:

现在我希望显示数字0到9,而不是星号。因此,最左侧的星号将被替换为0,第二个左起的星号将被替换为1,以此类推。当您达到9时,下一个数字再次变为零。

我不知道如何做到这一点。我看过像这样的波形模式,但它们是固定宽度的模式,而我的模式是可伸缩的。

我唯一能想到的方法是将输出转换为二维字符数组,然后从左到右手动刮掉*,将其替换为数字,然后打印它。然而,在较大的 x/yPrecision 值下,这会极大地消耗内存。

实现此输出的最优方法是什么?


输出正弦波的代码:

class sine {
  static final double xPrecision = 10.0; // (1/xPrecision) is the precision on x-values
  static final double yPrecision = 10.0; // (1/yPrecision) is the precision on y-values
  static final int PI = (int) (3.1415 * xPrecision);
  static final int TPI = 2 * PI; // twice PI
  static final int HPI = PI / 2; // half PI

  public static void main(String[] args) {
    double xd;

    for(int start = (int) (1 * yPrecision), y = start; y >= -start; y--){       
      double x0 = Math.asin(y / yPrecision),
            x1 = bringXValueWithinPrecision(x0),
            x2 = bringXValueWithinPrecision(x0 + TPI / xPrecision),
            x3 = bringXValueWithinPrecision(PI/xPrecision - x0);

      // for debug
      //System.out.println(y + " " + x0 + " " + x1 + " " + x2 + " " + x3);

      for(int x = 0; x <= TPI; x++){
        xd = (x / xPrecision);

        if(x1 == xd || x2 == xd || x3 == xd)
          System.out.print("*");
        else System.out.print(" ");      
      }

      System.out.println();
    }
  }

  public static double bringXValueWithinPrecision(double num){
      // obviously num has 16 floating points
      // we need to get num within our precision
      return Math.round(num * xPrecision) / xPrecision;
  }
}

你的代码是否总是能够打印完美正弦波?如果是这样的话,那么在 ** 处,也就是两个星号相连的地方,就代表着你已经拥有了整个正弦波对吗?第一部分(共 4 部分) /,你需要将其反转成 \\ 来得到第二部分,然后再将 /\\ 反转成 \\/ 来得到下半部分。(评论中似乎 \ 字符存在缺陷) - Adelin
@Adelin 我理解你的观点。虽然我不确定这如何解决我的当前问题。(是的,它有漏洞 \\\) - Gaurang Tandon
我刚刚添加了一个使用它的答案。 - Adelin
@Adelin 好的,收到。 - Gaurang Tandon
8个回答

7

首先在内存中“绘制”图形,然后给垂直点分配数字,并在单独的阶段打印它们。

               01                                              
           9        2                                          
         8            3                                        
        7              4                                       
      6                  5                                     
     5                    6                                    
    4                      7                                   
   3                        8                                  
  2                          9                                 
 1                            0                                
0                              1                              2
                                2                            1 
                                 3                          0  
                                  4                        9   
                                   5                      8    
                                    6                    7     
                                     7                  6      
                                       8              5        
                                        9            4         
                                          0        3           
                                              12               

请看代码中的注释以了解其工作原理:
static final double xPrecision = 10.0; // (1/xPrecision) is the precision on x-values
static final double yPrecision = 10.0; // (1/yPrecision) is the precision on y-values
static final int PI = (int) (3.1415 * xPrecision);
static final int TPI = 2 * PI; // twice PI
static final int HPI = PI / 2; // half PI

public static void main(String[] args) {
    // This part is the same as OP's code, except that instead of printing '*'
    // it stores the corresponding row number in the array of rows
    double xd;
    int[] row = new int[100];
    Arrays.fill(row, -1);
    int r = 0;
    int maxc = 0; // Mark the rightmost column of all iterations
    for(int start = (int) (1 * yPrecision), y = start; y >= -start; y--){       
      double x0 = Math.asin(y / yPrecision),
            x1 = bringXValueWithinPrecision(x0),
            x2 = bringXValueWithinPrecision(x0 + TPI / xPrecision),
            x3 = bringXValueWithinPrecision(PI/xPrecision - x0);
      int c = 0;
      for(int x = 0; x <= TPI; x++, c++){
        xd = (x / xPrecision);
        // This is where the asterisk used to go
        if(x1 == xd || x2 == xd || x3 == xd)
          row[c] = r;
      }
      maxc = Math.max(c, maxc);
      r++;
    }
    // Walk the assigned rows, and give each one a consecutive digit
    int[] digit = new int[100];
    int current = 0;
    for (int i = 0 ; i != 100 ; i++) {
        if (row[i] != -1) {
            digit[i] = (current++) % 10;
        }
    }
    // Now walk the rows again, this time printing the pre-assigned digits
    for (int i = 0 ; i != r ; i++) {
        for (int c = 0 ; c != maxc ; c++) {
            if (row[c] == i) {
                System.out.print(digit[c]);
            } else {
                System.out.print(' ');
            }
        }
        System.out.println();
    }
}

public static double bringXValueWithinPrecision(double num){
      // obviously num has 16 floating points
      // we need to get num within our precision
      return Math.round(num * xPrecision) / xPrecision;
}

代码的第一部分填充了row[i]数组,该数组包含列i中星号所在的行。从row[]数组中取出前几个数字,看起来像这样:

10 9 8 7 6 5 4 - 3 2 - 1 - - - 0 0 - - - 1 - 2 3 - 4 5 6 7 8 9 10

-代表具有 -1 值的单元格,表示缺失值。该数组表示最左边的星号在第10行,下一个星号在第9行,然后是8、7、6等。星号11和12位于顶部的第0行。

第二个循环遍历 rows,跳过 -1 并将连续数字分配给所有非负位置。

第三个循环再次按行遍历整个字段,在当前行与 row[] 数组中的值匹配时,从预分配的 digit[] 数组中打印值。

演示。


能否详细解释一下 maxc 的作用? - Gaurang Tandon
@GaurangTandon 这是我们曾经到达的最右边的列。你理解 row[]digit[] 数组的含义吗? - Sergey Kalinichenko
我正在尝试,但是我做不到。你能否写出你的代码的简短步骤性工作,用项目符号呈现?谢谢! - Gaurang Tandon
你为什么将row数组初始化为默认大小为100?这是因为它只是一个大于打印的星号总数的数字,还是其他原因? - Gaurang Tandon
1
处的值为0,在π处为1,在处变为了2。有些地方出了问题。所有在π处的值都应该是0 - Aniket Sahrawat

5
如果你替换:
System.out.print("*");

使用

System.out.print(""+(x%10));

看起来它几乎可以工作了。

               56                                              
           1        0                                          
         9            2                                        
        8              3                                       
      6                  5                                     
     5                    6                                    
    4                      7                                   
   3                        8                                  
  2                          9                                 
 1                            0                                
0                              1                              2
                                2                            1 
                                 3                          0  
                                  4                        9   
                                   5                      8    
                                    6                    7     
                                     7                  6      
                                       9              4        
                                        0            3         
                                          2        1           
                                              67               

也许需要进一步调整才能让它完美。

1
这将跳过没有星号的列中的数字。 - Sergey Kalinichenko
最上面的“156”不应该是“012”吗? - Adelin
取模运算对于x来说非常直观,因为它是唯一一个在水平方向上递增的操作,所以加1,但正如dasblinkenlight指出的那样,它会跳过一些数字 :( - Gaurang Tandon

2

通过完全不同的方式来实现,可以得到不同的结果,但是可以达到你想要的效果。

本质上,

for each y
  for each x
    calculate fx = sin(x)
    if fx == y print * else print space

这种方法计算 sin(x)x*y 的次数非常低效。如果您使用矩阵填充,只需计算 sin(x) x 次即可。

static final double xPrecision = 10.0; // (1/xPrecision) is the precision on x-values
static final double yPrecision = 10.0; // (1/yPrecision) is the precision on y-values

private void sine() {
    for (double y = 1; y >= -1; y -= 1.0 / yPrecision) {
        int n = 0;
        for (double x = 0; x < 2.0 * Math.PI; x += 1.0 / xPrecision, n++) {
            double fx = Math.sin(x);
            boolean star = Math.round(fx*xPrecision) == Math.round(y*yPrecision);
            System.out.print((star ? ""+(n%10) : " "));
        }
        System.out.println();
    }
}

public void test(String[] args) {
    sine();
}

提供给您:
             345678                                            
           12      901                                         
         90           2                                        
        8              34                                      
      67                 5                                     
     5                    6                                    
    4                      7                                   
   3                        8                                  
  2                          9                                 
 1                            0                                
0                              1                               
                                2                             2
                                 3                           1 
                                  4                         0  
                                   56                      9   
                                     7                    8    
                                      8                 67     
                                       9               5       
                                        01           34        
                                          23       12          
                                            4567890            

1
(+1) 另一种方法不使用数组! :D 顺便说一句:对于每个 x 计算 sin x 并将其与 y 进行比较(这段代码),而不是计算一次 asin y 然后将其与每个 x 进行比较(我的原始代码),在我看来效率更低。请看看您是否可以在原始答案中避免此限制。虽然它仍然很好 :) - Gaurang Tandon

1
这是我的解决方案,基本上使用了4个循环中的正弦一半:
  • 从一半到0
  • 从0到一半
  • 从一半到结尾
  • 从结尾到一半
在每个循环中只替换第一个星号。
class sine {
    static final double xPrecision = 14.0; // (1/xPrecision) is the precision on x-values
    static final double yPrecision = 14.0; // (1/yPrecision) is the precision on y-values
    static final int PI = (int)(3.1415 * xPrecision);
    static final int TPI = 2 * PI; // twice PI
    static final int HPI = PI / 2; // half PI

    public static void main(String[] args) {
        double xd;
        String str = "";
        for (int start = (int)(1 * yPrecision), y = start; y >= -start; y--) {
            double x0 = Math.asin(y / yPrecision),
                x1 = bringXValueWithinPrecision(x0),
                x2 = bringXValueWithinPrecision(x0 + TPI / xPrecision),
                x3 = bringXValueWithinPrecision(PI / xPrecision - x0);

            // for debug
            //System.out.println(y + " " + x0 + " " + x1 + " " + x2 + " " + x3);

            for (int x = 0; x <= TPI; x++) {
                xd = (x / xPrecision);

                if (x1 == xd || x2 == xd || x3 == xd)
                    str += "*";
                else str += " ";
            }
            str += "\n";
        }
        String[] rows = str.split("\n");
        int half = (int)(1 * yPrecision);

        // we use this half in for loops, from half to 0, from 0 to half, from half to the end and from the end to the half, and replace only the first asterisk.
        int val = 0;
        for (int i = half; i >= 0; i--) {
            if (val == 10) val = 0;
            rows[i] = rows[i].replaceFirst("\\*", Integer.toString(val++));
        }
        for (int i = 0; i <= half; i++) {
            if (val == 10) val = 0;


            rows[i] = rows[i].replaceFirst("\\*", Integer.toString(val++));
        }
        for (int i = half + 1; i < rows.length; i++) {
            if (val == 10) val = 0;
            rows[i] = rows[i].replaceFirst("\\*", Integer.toString(val++));
        }
        for (int i = rows.length - 1; i >= half; i--) {
            if (val == 10) val = 0;
            rows[i] = rows[i].replaceFirst("\\*", Integer.toString(val++));
        }

        System.out.println(String.join("\n", rows));
    }

    public static double bringXValueWithinPrecision(double num) {
        // obviously num has 16 floating points
        // we need to get num within our precision
        return Math.round(num * xPrecision) / xPrecision;
    }
}

结果:

               01                                              
           9        2                                          
         8            3                                        
        7              4                                       
      6                  5                                     
     5                    6                                    
    4                      7                                   
   3                        8                                  
  2                          9                                 
 1                            0                                
0                              1                              2
                                2                            1 
                                 3                          0  
                                  4                        9   
                                   5                      8    
                                    6                    7     
                                     7                  6      
                                       8              5        
                                        9            4         
                                          0        3           
                                              12               

关于“找到正弦函数的一半”,正弦波的一半是否总在距离顶部(start + 1)行处?(因为 y 值范围从 start 到 -start(都包括 start 和 -start)...) - Gaurang Tandon
这是正确的(虽然不是 start + 1 而是 start)。我没有真正研究整个正弦函数是如何创建的。我只是用 str 创建替换了直接打印并从那里开始。但确实,您可以跳过获取一半代码的部分。 - Adelin
1
我理解你在这里做的事情,赞同你的替代方案,但我正在寻找一种非基于数组的方法。此外,如果我将正弦波扩展到4pi或8pi,这段代码将失效。我们需要添加更多的“for”循环 :( - Gaurang Tandon
@GaurangTandon,你在问题陈述中的代码在处理更长时间段时不太具有可扩展性。为什么你没有明确说明这个要求呢? - David K
那可以进行优化。你给它一个 startLocation,和 updowndirection,并在该方向上无限循环 while(str.contains("*")),交替改变方向。 - Adelin
显示剩余2条评论

1
通过利用每行只有一个点(在每个斜率上)的事实,您可以计算在每个点显示哪个数字,而无需使用额外的内存或循环。这是我的示例。请注意,我仅检查了此示例仅在xPrecisionyPrecision为整数时才有效。如果要使用双精度,请修改它。
class sine {
    static final double xPrecision = 10.0; // (1/xPrecision) is the precision on x-values
    static final double yPrecision = 10.0; // (1/yPrecision) is the precision on y-values
    static final int PI = (int) Math.round(Math.PI * xPrecision);
    static final int TPI = 2 * PI; // twice PI
    static final int HPI = PI / 2; // half PI
    static final int cycles = 2; // prints from x=0 to 2*cycles*pi

    public static void main(String[] args) {
        double xd;
        int cycleoffset, cycleoffset2, topbottomoffset = 1;

        for (int start = (int) (1 * yPrecision), y = start; y >= -start; y--) {
            double x0 = Math.asin(y / yPrecision), x1 = bringXValueWithinPrecision(x0),
                    x2 = bringXValueWithinPrecision(x0 + TPI / xPrecision),
                    x3 = bringXValueWithinPrecision(PI / xPrecision - x0), tmp;

            if (y == start) {
                if (x1 == x3) // when there is only one point at the top/bottom
                    topbottomoffset = 0;
                else if (x1 > x3) // swap x1 and x3
                {
                    tmp = x1;
                    x1 = x3;
                    x3 = tmp;
                }
            } else if (y == -start) {
                // I don't think this is needed, but just for safety make sure there is only one point on the bottom if there was only one point at the top
                if (topbottomoffset == 0)
                    x2 = x3;
                else if (x2 < x3) // swap x2 and x3
                {
                    tmp = x2;
                    x2 = x3;
                    x3 = tmp;
                }
            }

            cycleoffset = (int) (4 * yPrecision + 2 * topbottomoffset);
            cycleoffset2 = -cycleoffset;

            int start1 = topbottomoffset + 2 * (int) yPrecision, start2 = 2 * topbottomoffset + 4 * (int) yPrecision;

            for (int x = 0, lim = cycles * TPI; x <= lim; x++) {
                xd = ((x % TPI) / xPrecision);
                if (x % TPI == 0)
                    cycleoffset2 += cycleoffset;

                // x = 0 to pi/2
                if (x1 == xd)
                    System.out.print((cycleoffset2 + y) % 10);
                // x = 3pi/2 to 2pi
                else if (x2 == xd)
                    System.out.print((cycleoffset2 + start2 + y) % 10);
                // x = pi/2 to 3pi/2
                else if (x3 == xd)
                    System.out.print((cycleoffset2 + start1 - y) % 10);
                else
                    System.out.print(" ");
            }

            System.out.println();
        }
    }

    public static double bringXValueWithinPrecision(double num) {
        // obviously num has 16 floating points
        // we need to get num within our precision
        return Math.round(num * xPrecision) / xPrecision;
    }
}

编辑 不同范围的数字计算方法如下:

0 < x < π/2:这是最简单的范围,因为它是第一个范围。由于中间行是 y=0,那就是正弦波开始的地方,我们可以使用 y 来找到数字。

π/2 < x < 3π/2:在这里,随着我们向下移动,数字逐渐增加,但 y 随着我们向下移动而减小。因此,我们必须使用一个 -y 项。在顶行,y=yPrecision,上一个范围的最后一个数字是 yPrecision。所以我们使用 2*yPrecision - y,因为它包括了 -y,并且在第一个术语(其中 y=yPrecision)等于 yPrecision。

3π/2 < x < 2π: 当我们向下移动时,这里的数字会倒数计算,因此我们需要一个+y项,但棘手的部分是确定从哪里开始。由于正弦波在这一点上已经从0到yPrecision到0到-yPrecision,因此底部点(x=3π/2)应该从3*yPrecision开始。由于底部点处y=-yPrecision,因此我们使用4*yPrecision + y,因为它包括一个+y,并且在第一个术语(其中y=-yPrecision)等于3*yPrecision。

topbottomoffset项:根据xPrecision和yPrecision的值,顶部和底部行可以绘制一个或两个点。如果有两个点,则需要将π/2到3π/2范围内的数字加1,并将3π/2到2π范围内的数字加2。

cycleoffset项:如果绘制多个正弦波周期,则需要从上一个周期中使用的最后一位数字开始。每个周期从0到yPrecision再到0到-yPrecision再到0,相当于4*yPrecision。因此,每个新周期都需要从4*yPrecision*[先前周期的数量]开始。如果顶部和底部行有两个点,则还需要考虑它们。

交换值:当顶部行有两个点时,则x1>x3。这是因为当y=yPrecision时,我们正在取Math.asin(1),这恰好在Java的double系统中为pi/2=1.5707963267948966。在较低的xPrecision(<100.0),由bringXValueWithinPrecision进行的舍入将x1提高到1.58,而将x3下降到接近1.56。因此,它们需要交换顺序才能得到正确的数值顺序。


我即使在xPrecision不等于yPrecision的情况下运行了你的代码,它也运行得非常好!哇!现在让我试着理解它... - Gaurang Tandon
我已经成功地将你的代码扩展到了从0到2pi的多个周期,因此我在你的帖子中添加了这一部分。请看看是否符合你的要求。另外,我不理解你是如何得出(2 * offset + 4 * yPrecision + y) % 10);和下面那个表达式的。请再详细解释一下。谢谢! - Gaurang Tandon
多波形显示正确,但我添加了循环偏移来解决在其他周期的不同数字处开始的问题。我也尝试写一些说明,希望能有所帮助! - Tobbs
我仍在摆弄你的代码。我找到了你最后一部分的问题,并给出了解释。我对当前代码的主要问题是,即使在一个 x 迭代中也进行了很多计算,因此不能简单地取 Math.sin(x),就像上面所做的。我添加了一些优化,但还在尝试更多... - Gaurang Tandon
我能够将连续计算简化为一个模运算。看一下吧! - Gaurang Tandon

1
关注不同的方法?
                                            3030              
                                          28    28            
                                        26        26          

                                      22            22        

                                    18                18      


                                  12                    12    


                                06                        06  


00                            00                            00


  06                        06                                


    12                    12                                  


      18                18                                    

        22            22                                      

          26        26                                        
            28    28                                          
              3030                                            

解决方案:

import static java.lang.Math.sin;
import static java.lang.Math.PI;
import static java.lang.Math.abs;

public class Sine {

    static final Integer points = 30; // points on x and y axis

    public static void main(String[] args) {

        // contains graph points
        Boolean[][] graph = new Boolean[points + 1][points + 1];

        for (Double x = 0.0; x <= points; x++) {
            // x axis pi value
            Double pi = (x / points) * 2 * PI;
            // sin(x) plot for x
            Integer sinx = (int) Math.round((sin(pi) * points / 2) + points / 2);
            graph[sinx][x.intValue()] = true;
        }

        for (Integer i = 0; i <= points; i++) {
            for (Integer j = 0; j <= points; j++) {

                // space characters on x axis
                Integer pt = (int) Math.floor(Math.log10(points) + 1);
                String space = String.format("%" + pt + "s", " ");

                // padding for p
                String p = String.format("%0" + (pt) + "d", abs(i - points / 2) * 2);

                System.out.print(graph[i][j] != null ? p : space);
            }
            System.out.println();
        }

    }

}

方法:

  • points 包含 x 轴和 y 轴上的字符数。

  • graph 对于每个 x 和 y 字符包含 truenull

  • 第一个循环:

    1. 由于正弦图中的 x 值范围为 0 到 2π,因此需要相应地转换 x。所以 pi 包含相同范围内但根据 x 的值而定的值。

    2. sinx 是根据 x 的值计算出的整数值。

    3. 无需解释 graph[sinx][x.intValue()] = true;

  • 第二个循环:

    • 第一个循环:

      • 执行 LOOPLABEL。

      • 在末尾中断到下一行。

    • 第二个循环(LOOPLABEL)

      • pt 保存 y 轴上的填充数字。

      • space 是要打印在 y 轴上的空格字符。

      • p 是在 0 到 points 范围内转换的值。

      • 打印 graph[i][j]

DEMO

可以翻译为:

{{链接1:演示}}


看起来真的很酷!:D 但我想知道你正在打印什么样的模式?“00,06,12,18,22,26,28,30”那是什么模式? - Gaurang Tandon
@GaurangTandon 这是points整数的范围。在你的情况下,它将是xPrecisionyPrecision - Aniket Sahrawat
@GaurangTandon 图表没有完全打印。已更新! - Aniket Sahrawat
1
@GaurangTandon 检查导入语句,它们是静态导入。当您静态导入一个方法时,您不需要使用完全限定名称来调用它们。现在我们来看下一个问题,原始类型不支持intValue()这样的方法,并且不能有nullBoolean可能有三个可能的值,而boolean只有其中的两个。坦白地说,我讨厌我的ide中显示的原始类型的颜色 :p - Aniket Sahrawat
1
你刚才说的只能来自于长期的Java编程经验,我今天学到了新的东西,所以太棒了!:D 我现在会用全新的精力去理解你的代码! - Gaurang Tandon
显示剩余2条评论

1
由于这是Java,那么我们如何使用一些对象作为对象来处理,而不仅仅是定义几个函数的地方。
将您的波浪形图形视为多个反正弦函数“分支”的组合。 (从数学上讲,这就是我们解释您程序版本如何使用Math.asin生成多个星星坐标的方式。) 分支0是曲线的初始上升部分, 分支1是分支0之后曲线的下降部分, 分支2是分支1之后曲线的上升部分,依此类推。 这些分支在输出的中间线处交叉,其x值分别为0,PI,2 * PI,3 * PI等。 根据您希望图形向右延伸的程度,很容易确定您需要多少个分支。 例如,要绘制从0到8 * PI的图形,您需要九个分支(分支0、分支8和两者之间的七个分支)。
您可以使用某个类的对象来实现每个分支,我们称之为ArcSineBranch。 它有一个构造函数ArcSineBranch(int),以分支号作为参数。 创建某种有序列表(可以是ArcSineBranch[]数组),并将这些分支对象放入其中, 确保分支号按顺序从0到所需的最大数字排列。
您还需要实现一些方法来告诉第一个ArcSineBranch其最左端在哪里-在问题示例中,第一个分支的最左端在y == 0,而对于所有其他上升分支,它在y == -start,对于所有下降分支,它在y == start
现在,您调用第一个ArcSineBranch的变异器函数,告诉它其最左边的符号是0。为了使算术更容易,现在将其视为整数(而不是字符串)。 然后,您查询第一个ArcSineBranch将要写入的最右边的符号,它可以从最左边的符号和它将在符号上写的行数计算出来。 您还查询它的右侧符号的x坐标。 (对象通过从PI的倍数中加或减Math.asin(y / yPrecision)的舍入倍数来计算任何y坐标的符号的x坐标。)
现在,对于列表中的每个ArcSineBranch,您将其传递给前一个分支写入的最右边的符号和x坐标。这个ArcSineBranch使用该信息来确定它所写的最左边的符号和该符号的y坐标。(我在这里关注y坐标,以防您选择了一个导致一个分支的最右边的x坐标与下一个分支的最左边的x坐标相同的xPrecision值; 我们应该仅在输出中写入一个符号,因此我们希望后面的分支跳过其最左边的x坐标,并将其最左边的符号写在下一个位置,一行向上或向下。但是,如果x坐标不同,我们希望后面的分支在同一行上写一个符号。)
现在,稍后的ArcSineBranch“知道”它将打印的最左边的符号及其y坐标,您可以查询它的最右边的符号和x坐标,并将其传递给下一个ArcSineBranch,依此类推。
一旦按照这种方式遍历了所有的ArcSineBranch对象,使每个对象都知道其分支需要写入哪些符号以及在何处写入它们,那么就可以循环for(y = start; y >= -start; y--); 在该循环内,您将循环遍历ArcSineBranch对象列表; 对于每个对象,您查询它是否需要在y坐标y处写入符号。 如果对象需要写入符号, 您查询要在哪个x坐标处写入哪个符号, 然后将输出向右间隔,直到达到该x坐标并在那里编写该符号。 但是当然,首先要检查这是否会在所需图形的右边缘之外绘制符号。 (这个检查实际上只适用于最后一个ArcSineBranch,因此您可以通过先循环遍历其他分支,然后单独处理最后一个ArcSineBranch来优化代码。)
我已经比最初想要的更详细地描述了这个算法。这里应该有足够的信息以相对直接的方式将其编码为Java,尽管仍然需要解决一些本地化细节。
请注意,本答案中的设计旨在使用与问题中的代码相同的数学思想来决定绘制点的位置。 具体来说,ArcSineBranch(0) 生成原始代码中的 x1 值,ArcSineBranch(1) 生成 x3 值,ArcSineBranch(2) 生成 x2 值。 实现此设计应在原始代码绘制的每个星号位置上绘制一个数字,并且不应绘制其他任何数字。

这确实使用了数组,但不是存储整个模式字符串,而是存储对象,这些对象存储打印数字的值的坐标。我会尝试把它写出来,然后再回复你。 - Gaurang Tandon
顺便说一下,我的代码确实打印了一个sine分支(因为我使用的是asin(y)而不是asin(x))。所以我不确定你为什么认为它是一个arcsine分支。 - Gaurang Tandon
1
我之所以说“反正弦”,是因为这是Math.asin的完整数学英文名称:“sin”前面的“a”代表“反向”。因此,你原来的代码基于“反正弦”函数,这很重要,因为这就是如何在曲线的每个上升或下降段上获得一颗星星的。你非常聪明。正如我们所看到的,当人们尝试直接使用正弦函数绘制曲线上的数字时,在上升和下降部分他们倾向于在一个y值上获得多个连续的数字,而不仅仅是在顶部或底部的行。 - David K
在数学术语中,“分支”一词用作反函数的修饰语:人们说“反正弦函数的一个分支”或“复对数函数的一个分支”。我从未在数学写作中看到过“正弦函数的一个分支”这样的词。但你是对的,我们正在绘制各种上升和下降的正弦函数线段,而不是反正弦函数。因此,“ArcSineBranch”仅是程序实现的一部分;它并不描述输出。我们通过将反正弦函数的分支“横向”绘制来将其转换为正弦函数的线段。 - David K
所以它被称为“ArcSine”,因为我们使用 Math.asin,而且被称为“Branch”,因为我们需要 x2x3 值,而不仅仅是 x1 - David K
显示剩余2条评论

-2
在你的循环中添加一个计数器,并在达到9时将其重置:
for(int x = 0, counter = 0; x <= TPI; x++, counter++){
    xd = (x / xPrecision);

    if(x1 == xd || x2 == xd || x3 == xd) {
      System.out.print("" + counter);

      if (counter == 9) {
          counter = 0;
      }
    } else {
        System.out.print(" ");      
    }
}

2
他逐行打印,所以正弦图形的顶部将会显示“0 1”,接下来一行是“2 3”,如此类推。 - Sergey Kalinichenko
1
@dasblinkenlight 没错,这就是我面临的问题!这段代码将会把最上方的 * 打印为 0,然后第二行的打印为 1。它不是从左到右,而是从上到下。但无论如何,还是感谢你的尝试 Georg :) - Gaurang Tandon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接