背景
- 我非常喜欢编程语言,之前写过rust、R、python、C++等。
- 我的第一门语言就是R语言,然后在比较掌握R语言之后,又花了很长一段时间学习RCPP。
- 我觉得不管是会R还是说会python,都应该会C\C++。
- C\C++运行效率太顶了。牛!
主要内容
最近也刚好C之类的内容,这里就简单分享一个我遇到的非常有意思的内容:使用C和python两种编程语言、通过蒙特卡洛方法计算圆周率PI。
蒙特卡洛计算圆周率PI
蒙特卡洛计算圆周率PI其实是一个非常经典的案例,在R仿真里面,也都有。
基本上案例如下:
- 在一个边长为1的正方形里面,有一个半径为1/2的圆。
- 正方形和圆共一个中心点。圆内切正方形。
- 向这个正方形里面投点,计算点落在圆内的数量。落在圆内点的数量比上总点数就是等于 π / 4 \pi/4 π/4。
那么按照这个思想,只要是不断的生成若干个点,计算占比即可。
C代码
这里先分享一个C语言的代码:
#include <stdlib.h>
#include <stdio.h>
#include <chrono>
#include <array>
#define N_POINTS 10000000
#define N_REPEATS 5
float estimate_pi(int n_points) {
double x, y, radius_squared, pi;
int within_circle=0;
for (int i=0; i < n_points; i++) {
x = (double)rand() / RAND_MAX;
y = (double)rand() / RAND_MAX;
radius_squared = x*x + y*y;
if (radius_squared <= 1) within_circle++;
}
pi=(double)within_circle/N_POINTS * 4;
return pi;
}
int main() {
double avg_time = 0;
srand(42);
for (int i=0; i < N_REPEATS; i++) {
auto begin = std::chrono::high_resolution_clock::now();
double pi = estimate_pi(N_POINTS);
auto end = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin);
avg_time += elapsed.count() * 1e-9;
printf("Pi is approximately %g and took %.5f seconds to calculate.\n", pi, elapsed.count() * 1e-9);
}
printf("\nEach loop took on average %.5f seconds to calculate.\n", avg_time / N_REPEATS);
}
这里在clion里面运行一下,可以看到非常的快,基本上都是在0.19秒左右。
python代码
既然c语言这么快,那python是什么情况,运行效率如何,这里给到python代码:
import random
import time
import argparse
def estimate_pi(
n_points: int,
show_estimate: bool,
) -> None:
"""
Simple Monte Carlo Pi estimation calculation.
Parameters
----------
n_points
number of random numbers used to for estimation.
show_estimate
if True, will show the estimation of Pi, otherwise
will not output anything.
"""
within_circle = 0
for _ in range(n_points):
x, y = (random.uniform(-1, 1) for v in range(2))
radius_squared = x**2 + y**2
if radius_squared <= 1:
within_circle += 1
pi_estimate = 4 * within_circle / n_points
if not show_estimate:
print("Final Estimation of Pi=", pi_estimate)
def run_test(
n_points: int,
n_repeats: int,
only_time: bool,
) -> None:
"""
Perform the tests and measure required time.
Parameters
----------
n_points
number of random numbers used to for estimation.
n_repeats
number of times the test is repeated.
only_time
if True will only print the time, otherwise
will also show the Pi estimate and a neat formatted
time.
"""
start_time = time.time()
for _ in range(n_repeats):
estimate_pi(n_points, only_time)
if only_time:
print(f"{(time.time() - start_time)/n_repeats:.4f}")
else:
print(
f"Estimating pi took {(time.time() - start_time)/n_repeats:.4f} seconds per run."
)
def positive_integer(value: str) -> int:
"""Check for positive integer in arg_parse."""
int_value = int(value)
if int_value <= 0:
raise argparse.ArgumentTypeError(f"{value} is an invalid positive int value")
return int_value
def main(arguments=None):
"""Main loop in arg parser."""
parser = argparse.ArgumentParser()
parser.add_argument(
"-p",
"--n_points",
help="Number of random points to use for estimating Pi.",
type=positive_integer,
default=1_000_000,
)
parser.add_argument(
"-r",
"--n_repeats",
help="Number of times to repeat the calculation.",
type=positive_integer,
default=5,
)
parser.add_argument(
"--only-time",
action='store_true',
default=False,
)
args = parser.parse_args()
run_test(
args.n_points,
args.n_repeats,
args.only_time,
)
if __name__ == "__main__":
main()
这里是python的运行结果,基本上在1.5秒左右
比较与总结
- 上面两个其实都不太公平,因为我的C语言代码是在WSL2里面运行的,cpu都是有损耗的情况下。跑出个0.19秒。
- 上面的python代码我是直接使用anaconda环境跑的。跑出个1.5秒左右。
- 基本上C语言的运行时间是python的10倍左右。
- 其实大家如果直接看上面的C代码,发现好像C语言代码也没那么难读。C语言的语法看着还挺现代的。
下图是各个版本的python和C语言的运行效率对比:C语言基本上是要比python快个10倍左右。
其实在科学计算领域,目前最火的就是python和C++。那如果真的是两个都会,确实就无敌了!
不多说了,我去学习C++了!
更多推荐
python vs C++ 谁更快
发布评论