加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

Newbie Scala关于简单数学运算的问题

发布时间:2020-12-16 19:05:24 所属栏目:安全 来源:网络整理
导读:新手 Scala问题: 说我想在Scala中这样做[Java代码]: public static double[] abs(double[] r,double[] im) { double t[] = new double[r.length]; for (int i = 0; i t.length; ++i) { t[i] = Math.sqrt(r[i] * r[i] + im[i] * im[i]); } return t;} 并且
新手 Scala问题:

说我想在Scala中这样做[Java代码]:

public static double[] abs(double[] r,double[] im) {
  double t[] = new double[r.length];
  for (int i = 0; i < t.length; ++i) {
    t[i] = Math.sqrt(r[i] * r[i] + im[i] * im[i]);
  }
  return t;
}

并且使它成为通用的(因为Scala有效地执行了我读过的通用原语).只依靠核心语言(没有图书馆对象/课程,方法等),怎么做呢?真的,我根本看不出怎么做,所以我猜这只是一个纯粹的奖励点问题.

我遇到很多问题,试图做这个简单的事情,我暂时放弃了Scala.希望一旦我看到Scala的方式,我会有一个’aha’的时刻.

更新:
与他人讨论,这是迄今为止我发现的最好的答案.

def abs[T](r: Iterable[T],im: Iterable[T])(implicit n: Numeric[T]) = {
   import n.mkNumericOps                                                   
   r zip(im) map(t => math.sqrt((t._1 * t._1 + t._2 * t._2).toDouble))          
}

解决方法

在scala中执行通用/执行原语实际上涉及scala用于避免拳击/拆箱的两个相关机制(例如,在java.lang.Integer中包装一个int,反之亦然):

> @specialize类型注释
>使用清单与数组

specialize是一个注释,告诉Java编译器创建代码的“原始”版本(类似于C模板,所以我被告知).查看Tuple2(这是专门)的类型声明与List(不是)相比.它在2.8中被添加,这意味着,例如像CC [Int] .map(f:Int => Int)这样的代码被执行,没有任何ints(假设CC是专门的,当然!).

清单是在scala中执行reified类型的方法(受JVM的类型擦除限制).当您想要在某种类型T上通用化方法,然后在方法中创建一个T(即T [])数组时,这一点特别有用.在Java中,这是不可能的,因为新的T []是非法的.在scala这可以使用清单.特别地,在这种情况下,它允许我们构造一个原始的T数组,如double []或int []. (这真棒,万一你想知道)

拳击从性能角度来说非常重要,因为它创建垃圾,除非你的所有int都是< 127.它显然还增加了额外的流程步骤/方法调用等级的间接.但是,除非你绝对肯定地确定你绝对会做(大多数代码不需要这样的微优化) 所以,回到这个问题:为了做到这一点没有拳击/拆箱,你必须使用Array(List不是专门的,即使是这样,也会更加挨饿)!一对集合上的压缩功能将返回一组Tuple2s(它不需要拳击,因为这是专门的). 为了一般地(即跨各种数值类型)执行此操作,您必须要求在通用参数上上下文绑定数字,并且可以找到一个清单(阵列创建所需).所以我开始沿着…

def abs[T : Numeric : Manifest](rs : Array[T],ims : Array[T]) : Array[T] = {
    import math._
    val num = implicitly[Numeric[T]]
    (rs,ims).zipped.map { (r,i) => sqrt(num.plus(num.times(r,r),num.times(i,i))) }
    //                               ^^^^ no SQRT function for Numeric
}

…但它不是很有效.原因是“通用”数值没有像sqrt – >所以你只能在知道你有双人的时候做到这一点.例如:

scala> def almostAbs[T : Manifest : Numeric](rs : Array[T],ims : Array[T]) : Array[T] = {
 | import math._
 | val num = implicitly[Numeric[T]]
 | (rs,i) => num.plus(num.times(r,i)) }
 | }
almostAbs: [T](rs: Array[T],ims: Array[T])(implicit evidence$1: Manifest[T],implicit     evidence$2: Numeric[T])Array[T]

优秀 – 现在看到这个纯粹的泛型方法做一些东西!

scala> val rs = Array(1.2,3.4,5.6); val is = Array(6.5,4.3,2.1)
rs: Array[Double] = Array(1.2,5.6)
is: Array[Double] = Array(6.5,2.1)

scala> almostAbs(rs,is)
res0: Array[Double] = Array(43.69,30.049999999999997,35.769999999999996)

现在我们可以sqrt的结果,因为我们有一个Array [Double]

scala> res0.map(math.sqrt(_))
res1: Array[Double] = Array(6.609841147864296,5.481788029466298,5.980802621722272)

并证明这将工作,甚至与另一个数字类型:

scala> import math._
import math._
scala> val rs = Array(BigDecimal(1.2),BigDecimal(3.4),BigDecimal(5.6)); val is =     Array(BigDecimal(6.5),BigDecimal(4.3),BigDecimal(2.1))
rs: Array[scala.math.BigDecimal] = Array(1.2,5.6)
is: Array[scala.math.BigDecimal] = Array(6.5,is)
res6: Array[scala.math.BigDecimal] = Array(43.69,30.05,35.77)

scala> res6.map(d => math.sqrt(d.toDouble))
res7: Array[Double] = Array(6.609841147864296,5.481788029466299,5.9808026217222725)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读