F#性能比例如Java我在做什么错了?

如何解决F#性能比例如Java我在做什么错了?

我目前正在尝试使用F#进行编程。因此,我编写了一个简单的F#脚本,以非常愚蠢的方式计算PI。我已经用许多编程语言编写了该算法,但是这次它的执行速度很慢,而且我不知道自己在做什么错。 与我的Java版本相比,这要慢10到20倍(在我按ALT键和Enter键以VS代码运行的计算机上,大约10-15瑞典克朗),这很多(我认为)。

算法的想法是将飞镖扔在一个1乘1的正方形中,其中有一个圆。圆接触正方形的边缘。如果飞镖击中了圆圈,它将被计算在内。投掷所有飞镖后,您只需将飞镖命中数除以飞镖总数,再乘以4即可得到PI。

我已经尝试了很多方法来得到我的错误,但是找不到它。

  • 我试图用固定值替换随机数生成->没做多少
  • 我试图用恒定值替换Math.Sqrt->没做多少
  • 我希望将Seq.xxx调用替换为Array,同时希望这样做可以减少开销。 ->做得不多

PS:我知道这种计算Pi的方法很烂。但这不是我想在这里提出的重点。

open System

let random = Random(DateTime.Now.Millisecond)
let throwDart i = (random.NextDouble(),random.NextDouble())

let distance dart point = let (x1,y1),(x2,y2) = dart,point
                          (x2 - x1,y2 - y1)
let length distance = let (x,y) = distance
                      Math.Sqrt(x * x + y * y)

let isInside circle dartHit = 
        let (center,radius) = circle 
        distance center dartHit |> length  |> (fun x -> x < radius)

let circle = ((0.5,0.5),0.5)

let dartCount = 100000000

let dartSeqence = Seq.init dartCount throwDart
let pi = float(dartSeqence |> Seq.filter (isInside circle) |> Seq.length) / float(dartCount) * 4.0

也许有人知道我在做什么错。我希望F#在此任务中能胜任,因为它是一种非常简单直接的算法。

非常感谢您的帮助。


更新1:

嗨,再次运行Java代码后,我感到有些失望,因为我认为它更快。这是大约运行的代码。在我的机器上4.4秒:

import java.util.Random;

public class DartThrower{
    Random random;

    public DartThrower(){
        random = new Random();
    }
    public boolean throwDart(){
        double x = random.nextDouble();
        double y = random.nextDouble();
        // wenn Entfernung des Punktes vom Mittelpunkt (0.5|0.5) größer als 0.5 ist wird false ausgegeben
        boolean inTheCircle = Math.sqrt((0.5 - x) * (0.5 - x) + (0.5 - y) * (0.5 - y)) <= 0.5;  
        return inTheCircle;
    }
}

class PiCalculator{
    public static void main(String[] args){
        long start = System.currentTimeMillis();
        double hitCount = 0.0;
        double throwCount = 100000000L;
        DartThrower thrower = new DartThrower();

        for (long i = 0; i < throwCount; i++){
            boolean hit = thrower.throwDart();
            hitCount += hit ? 1 : 0;
        }
        double a = hitCount / throwCount;
        double pi = a * 4.0;
        System.out.println("Pi= " + pi);
        System.out.println("took " + (System.currentTimeMillis() - start) + "ms");
    }
}

很抱歉,但是我认为时间不到1秒-这就是为什么我说的执行速度要快10到20倍。 不对!在确定了我的计时有多错误之后,我决定为两者都添加一些时间戳,并得到

  • Java:大约。 4.3秒
  • F#:大约13.0秒

因此在这两者之间是3-4的系数。如果我尝试使用@Tomas Petricek的性能更新,则此差异可能已过时。我会尽力告诉您结果。

感谢您的帮助。

解决方法

通过用一个简单的可变变量和一个for循环替换惰性序列,可以使此过程快2倍(在性能关键的F#代码中这没什么不好的):

let mutable count = 0
for i in 0 .. dartCount do
  if isInside circle (throwDart i) then count <- count + 1
let pi = float count / float dartCount * 4.0

通过制作函数inline,可以提高性能(在我的粗略测试中大约为30%),这可以消除一些以元组为单位的值装箱:

let inline distance dart point = 
  let (x1,y1),(x2,y2) = dart,point
  (x2 - x1,y2 - y1)

let inline length distance = 
  let (x,y) = distance
  Math.Sqrt(x * x + y * y)

let inline isInside circle dartHit = 
  let (center,radius) = circle 
  length (distance center dartHit) < radius

有了这个,我看不到任何明显的问题(但是我可能遗漏了一些东西)。最好查看Java代码进行比较,因为可能会有一些细微的逻辑更改会影响性能。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-