【问题标题】:Java version of matlab's linspacejava版matlab的linspace
【发布时间】:2011-06-01 23:26:57
【问题描述】:

matlab 的冒号运算符或 linspace 是否有 java 版本?例如,我想为均匀间隔的数字创建一个 for 循环,但我不想费心手动创建这些数字的数组。

例如要获取从 1 到 30 的所有整数,在 matlab 中我会输入:

1:30

linspace(1,30)

【问题讨论】:

标签: java matlab


【解决方案1】:

对于两个变量的调用,@x4u 是正确的。三变量调用会比较难模拟。

例如,我认为 linspace(1,30,60) 应该产生值 1, 1.5, 2, 2.5, 3, 3.5...,或者这可能是 linspace(1,30,59) 的值- - 无论如何,同样的问题。

使用这种格式,您必须自己进行计算——我个人会创建一个新对象来为我完成所有工作,而忘记 for 循环。

counter=new Linspace(1,30,60);
while(counter.hasNext()) {
    process(counter.getNextFloat())
}

或者干脆

while(float f : new Linspace(1,30,60)) {
    process(f);
}

如果你有你的 Linspace 对象实现 Iterable。

那么计数器对象的内部应该很容易实现,它会很容易地与你交流它正在做什么,而不会用一堆数字计算来混淆你的代码来计算比率。

实现可能是这样的: (注意:未经测试,我很确定这很容易受到边缘情况和浮点错误的影响!它也可能无法处理 end

public class Linspace {
    private float current;
    private final float end;
    private final float step;
    public Linspace(float start, float end, float totalCount) {
        this.current=start;
        this.end=end;
        this.step=(end - start) / totalCount;
    }
    public boolean hasNext() {
        return current < (end + step/2); //MAY stop floating point error
    }
    public float getNextFloat() {
        current+=step;
        return current;
    }
}

【讨论】:

    【解决方案2】:

    你想这样做吗?

    for( int number = 1; number <= 30; ++number )
    

    如果您需要它们以固定数量间隔,即3,您可以这样写:

    for( int number = 1; number <= 30; number += 3 )
    

    for 循环的左边部分初始化变量,中间部分是在每次迭代之前评估的条件,右边部分是在每次迭代之后执行的。

    【讨论】:

      【解决方案3】:

      实际上,我只需要为我正在处理的 java 项目执行此操作。我想确保它的实现方式与在 MATLAB 中相同,所以我首先编写了一个 MATLAB 等价物:

      function result = mylinspace(min, max, points)  
      answer = zeros(1,points);  
          for i = 1:points  
      answer(i) = min + (i-1) * (max - min) / (points - 1);  
      end  
      result = answer;  
      

      我对内置的 linspace 函数进行了测试,它返回了正确的结果,因此我将其转换为静态 java 函数:

      public static double[] linspace(double min, double max, int points) {  
          double[] d = new double[points];  
          for (int i = 0; i < points; i++){  
              d[i] = min + i * (max - min) / (points - 1);  
          }  
          return d;  
      }  
      

      在我看来,这比为这个函数创建一个新类要简单得多。

      【讨论】:

        【解决方案4】:

        我认为 Bill K 的想法是正确的,但我认为没有必要有一个 Linspace 类。

        // If you write linspace(start,end,totalCount) in Matlab ===>
        
        for(float i = start; i < end; i += (end-start)/totalCount)
            something(i);
        

        【讨论】:

        • 没有想到浮点数在 for 循环中可以正常工作。尽管如此,在浮动错误的情况下,您的情况并不总是正常工作,在那个问题和其他问题之间,我宁愿让东西集中起来。另外我认为 for(float f : Linspace) 代码更简洁、更明显(添加类通常有助于提高可读性)
        • 为什么不能正常工作?如果比较 i == end,浮点舍入错误会导致问题,但如果与 或 >= 比较则不会,这确实很好。另外,如果你想在for-each循环中使用Linspace,那么它必须实现Iterable,因此实现起来有点复杂(你也需要实现一个迭代器类,并在其中放置hasNext()和next()) .最后,它必须是一个 Iterable extends Number>,这意味着每个数字都将被包装到一个对象中,然后在运行时解包,如果您在大间隔上进行迭代,这可能效率低下。
        • 哦,而且--编译器实际上会拒绝任何尝试在 Linspace 上进行 for-each 迭代的代码,使用您帖子中的当前 Linspace 代码,因为它没有正确实现 Iterable。
        • 如果它应该在按钮上右击(比如在 50.0 结束)并且它有可能是 50.0001 或 49.9998 的错误 - 这将导致以一种或另一种错误方式关闭.您可以通过添加或减去少量来修复它,但是每次使用它时都要复制您的修复。此外,意图隐藏在此代码中,如果您创建一个对象,它可以很明显,并且该解决方案更易于阅读 - 为什么不使用对象?不过你是对的,它还没有实现可迭代——如果你不知道怎么做,我可以为你做——我只是认为添加起来很简单。
        • 顺便说一句,我不认为“Linspace”是显而易见的,除非对使用它的人来说——这是我回答的目标。如果是我,我会称之为“iterateOver”之类的。
        【解决方案5】:

        我自己正在寻找这个问题的解决方案,并研究了 MatLab 如何实现其 Linspace。我或多或少地将它转换为 Java 并最终得到了下面的方法。据我测试,它工作得很好,你得到了端点。与大多数情况一样,可能存在浮点错误。

        我不确定这是否存在版权问题。

        public static List<Double> linspace(double start, double stop, int n)
        {
           List<Double> result = new ArrayList<Double>();
        
           double step = (stop-start)/(n-1);
        
           for(int i = 0; i <= n-2; i++)
           {
               result.add(start + (i * step));
           }
           result.add(stop);
        
           return result;
        }
        

        【讨论】:

          【解决方案6】:

          如果您想使用 Java Streams,一种选择是:

              public static Stream<Double> linspace(double start, double end, int numPoints) {
                  return IntStream.range(0, numPoints)
                      .boxed()
                      .map(i -> start + i * (end - start) / (numPoints - 1));
              }
          

          【讨论】:

          • 或者,增加 1,IntStream.rangeClosed(0, numPoints).toArray()
          【解决方案7】:

          这是适用于 matlab 的主要算法,您可以将其转换为 Java,并提供所有 OOP 详细信息:

          >>> st=3;ed=9;num=4;
          >>> linspace(st,ed,num)
          
          ans =
          
               3     5     7     9
          >>> % # additional points to create (other than 3)
          >>> p2c=num-1;
          >>> % 3 is excluded when calculating distance d.
          >>> a=st;
          >>> d=ed-st;
          >>> % the increment shall calculate without taking the starting value into consideration.
          >>> icc=d/p2c;
          
          >>> for idx=[1:p2c];
          a(idx+1)=a(idx)+icc;
          end;
          >>> a
          
          a =
          
               3     5     7     9
          
          >>> diary off
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-11-19
            • 1970-01-01
            • 2013-03-31
            • 1970-01-01
            • 2015-06-25
            • 2015-01-17
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多