将正弦波打印到控制台

4

我正在开发一个Java程序,它可以在控制台上打印正弦波。以下是我目前为止编写的代码:

int num = 7;
for (double y = 2; y >= 0; y-=0.2) {
  for (double x = 0; x <= num; x+=0.2) {
    if ( ((0.1+x) >= Math.asin((double)y-1)) && (((double)x-0.1) <= Math.asin((double)y-1)) )
      System.out.print('*');
    else
      System.out.print(' ');
  }
  System.out.println();
}

本程序将每行的每个字符视为坐标平面上的0.2 x 0.2面积。如果正弦函数经过该面积,则在屏幕上打印星号。否则,打印空格。 运行时,将打印以下内容到控制台:

        *                          
     *                             
   *                               
  *                                
 *                                 
*                                  

有人能告诉我为什么我的程序在打印出波浪图的第一部分后停止了吗?

1
这是因为 asin 永远不会给你一个在 -pi..pi 之外的值。另一方面,sin 是周期性的,所以你可以尝试使用它(演示)。 - Sergey Kalinichenko
好的!所以我一直从错误的角度来处理这个问题。感谢您的演示! - quinten
4个回答

1
它只打印正弦波的前一刻度,这是因为Math.asin的范围所示:

返回值的反正弦;返回的角度在-pi/2到pi/2之间。

一旦你将x推进过Math.PI / 2,那么if语句的条件将始终为false
你可以利用以下事实:

sin(π - x) = sin(x)

sin(2π - x) = -sin(x)

通过包括更多的条件来利用它。(我还删除了不必要的double转换以提高清晰度。)
if ( (0.1+x >= Math.asin(y-1)) && (x-0.1 <= Math.asin(y-1)) ||
     (0.1+x >= Math.PI - Math.asin(y-1)) && (x-0.1 <= Math.PI - Math.asin(y-1))
     (2*Math.PI -(0.1 + x) <= -Math.asin(y-1)) && (2*Math.PI -(x-0.1) >= -Math.asin(y-1))  )

输出:

        *                          
     *     *                       
   *        *                      
  *           *                  * 
 *             *                *  
*               *              *   
                 *            *    
                  *          *     
                   *        *      
                    *      *       
                        *          

这个if语句明显比我写的好——它能正常工作。但是如果我想进一步扩展图形,就需要添加更多的条件。必须有一种更有效的方法来扩展图形,而不是反复添加if语句。 - quinten
1
是的,您可以将其扩展到当前范围之外。利用sin(2π + x) = sin(x)这个事实,并进行数学计算(mod 2π)。在循环内部,使用double x2pi = x % (2*Math.PI),然后使用x2pi执行if语句。 - rgettman

0

编辑:哎呀,我看代码的速度太快了,这是错误的。

你把num设为7,然后在循环中将x从0到num-1取值,因此你只是在遍历7列。增加num,你的图表应该会添加额外的列。如果你想要图表扩展到负数,你还需要增加你遍历的y值的范围。

然而,你的算法效率极低。对于你图表上的每个正方形,你都计算了两次asin(y-1),当你实际上只需要在每列中计算一次sin(x)。为什么不使用预先计算好的正弦值填充一个数组,然后在绘制图表时查询该数组呢?(当然,我知道在现代计算机上,无论哪种方式都足够快,几乎没有影响。)


感谢你的回答!是的,num = 7,但我的循环增量为0.2,因此应该覆盖波形略超过一个周期。数组的想法很聪明,我想我可以从那个角度来解决这个问题。 - quinten
如果这个回答解决了你的问题,你可以点击绿色打勾来接受它。这让其他用户知道问题已经被满意地回答了。 - user1618143
“num”与此无关我认为。 x增加了0.2,因此循环次数远远超过7次...正确答案在评论中由dasblinkenlight给出。 - fishi0x01
@fishi:哦,你说得对。我看代码的速度有点太快了。 - user1618143

0

问题似乎出现在您的 if 语句条件上,它几乎总是评估为 false。您应该检查条件表达式背后的计算。我发现增加 num 在这里并没有真正帮助。

也许您应该用其他字符替换空格,例如将 System.out.print(' '); 替换为 System.out.print('_');。这样您可能能够找出程序行为异常的原因。重新设计您的算法也可能有所帮助。


我认为if语句应该有90%的时间是false。否则,函数将会非常不明确。谢谢您的回答! - quinten

0
谢谢大家的帮助!根据 @dasblinkenlight 的建议,使用 sin 而不是 asin,我找到了一个非常简单的解决方案:
int num = 7;
for (double y = 1; y >= -1; y-=0.2) {
  for (double x = 0; x <= num; x+=0.2) {
    double sin = Math.sin(x);
    if ( (0.1+y) >= sin && (y-0.1) <= sin )
      System.out.print('*');
    else
      System.out.print(' ');
  }
  System.out.println();
}

这将在控制台上打印出以下内容:

      *****                        
    **     *                       
   *        **                     
  *           *                  **
 *             *                *  
*               *              *   
                 *            *    
                  *          *     
                   *        *      
                    **    **       
                      ****         

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