用Mathematica计算物理题

昨天在做电磁学题目的时候遇到几个手算比较麻烦的式子,于是改用Mathematica软件完成了计算。

在这里总结两个解决方法:

1、做近似计算,略去高阶小量

有一道题要计算 \(r \gg l\) 时的电势分布,原始的式子是(去掉了常数部分)

$$\frac{1}{{\sqrt {{l^2} + 2lr\cos (\theta ) + {r^2}} }} + \frac{1}{{\sqrt {{l^2} – 2lr\cos (\theta ) + {r^2}} }} – \frac{2}{r}$$

在Mathematica中可以用Series函数计算这个函数在 \(l=0\) 处的泰勒展开,展开到第二项就可以了。

Mathematica输入如下:

Assuming[r>0,Simplify[Series[-2/r+1/Sqrt[r^2+l^2-2r l Cos[\[Theta]]]+1/Sqrt[r^2+l^2+2 r l Cos[\[Theta]]],{l,0,2}]]]

得到的结果是:

$$\frac{{\left( {1 + 3\cos \left[ {2 \theta} \right]} \right){l^2}}}{{2{r^3}}} + O{\left[ l \right]^3}$$

第一项就是所求。

2、在极坐标系中求梯度

根据刚才算出来的电势求电场强度矢量,需要在极坐标系中求梯度。

用Mathematica的Grad函数,输入如下:

Assuming[r>0,Simplify[-Grad[((1+3 Cos[2 \[Theta]]) l^2)/(2 r^3),{r,\[Theta],\[Phi]},"Spherical"]]]

得到的结果是:

$$\left\{ {\frac{{3{l^2}\left( {1 + 3\cos \left[ {2\theta } \right]} \right)}}{{2{r^4}}},\frac{{3{l^2}\sin \left[ {2\theta } \right]}}{{{r^4}}},0} \right\}$$

这里用的是球面坐标系,所以结果的第三个分量是0,可以略去。前两个分量分别代表\(r\)方向和\(\theta\)方向的结果。

【π Day】一段很短的计算圆周率的代码

今天是3月14日,圆周率日。

我在网上看到了一段很短的计算圆周率的代码,可以算到8000位。我把程序输出的结果和Mathematica的结果比较了一下,验证了程序是正确的。

通过更改c的值和f数组的大小,可以算到更多的位。

我没弄明白这段代码的原理,如果有谁知道,欢迎在回复中告诉我。

简短版:

#include<stdio.h>
int a=10000,b=0,c=28000,d,e=0,f[28010],g;
main(){
for(;b-c;)f[b++]=a/5;
for(;d=0,g=c*2;c-=14,printf("%04d",e+d/a),e=d%a)
for(b=c;d+=f[b]*a,f[b]=d%--g,d/=g--,--b;d*=b);
}

正常版:
继续阅读“【π Day】一段很短的计算圆周率的代码”

C语言中的gets()与fgets()

C语言中gets(char*);可以从标准输入中读入一行字符,存入字符串;而用fgets(char*,int,FILE*)可以从文件读入一行字符,其中的整型参数指的是缓冲区大小。

我之前以为get(s)和fgets(s,length,stdin)在不考虑溢出的问题时,行为是完全相同的,但是今天发现它们有个细微的差别。

继续阅读“C语言中的gets()与fgets()”

只用位运算来写整数四则运算程序

整数在计算机中是以二进制形式存储的,整数的运算归根到底是二进制位的逻辑运算。

那么如何用最基本的位运算来实现整数的四则运算?

我今天写了“加”、“减”、“乘”、“除”、“取余”和“取相反数”这几种基本运算,代码中只用到了位运算。

我选择的是short型数值,并用代码循环了所有可能的情况(两个操作数分别从-32768到32767),可以验证我的运算函数的结果和直接做运算的结果是完全相同的(包括溢出的情况)。这些函数经过简单修改很容易支持更多位的整数。

有符号整数右移操作会复制符号位,我把一些函数的参数设置成了unsigned类型的,但是调用函数的时候可以直接传进有符号数。“加”、“减”、“乘”函数传进无符号数也可以得到正确结果。

由于有符号数中负数比正数多一个-32768,所以为了让程序支持边界条件,除法运算中所有操作都是针对负数进行的。

下面附代码:

继续阅读“只用位运算来写整数四则运算程序”

不同“距离”概念下的单位圆

昨天数学分析课上讲了“距离”概念的推广。

广义的“距离”(明可夫斯基距离)定义为

$${P_\alpha }\left( {\left( {{x_1},{y_1}} \right),\left( {{x_2},{y_2}} \right)} \right) = {\left( {{{\left| {{x_1} – {x_2}} \right|}^\alpha } + {{\left| {{y_1} – {y_2}} \right|}^\alpha }} \right)^{\frac{1}{\alpha }}}$$

其中\(\alpha =1\)时为曼哈顿距离,\(\alpha =2\)时为欧氏距离。

对于不同的“距离”可以画出对应的单位圆(即到原点“距离”为1的点的集合)

当\(\alpha\)从0变化到4时,单位圆的形状的变化很有趣,我做了下面的动态图:

circle

注:\(\)\alpha <1[/latex]时不满足“距离”的定义,但是也可以画出对应的单位圆。 如果把这种“单位圆”推广到三维空间,也可以作出很有趣的图,例如下面是[latex]x^4+y^4+z^4=1[/latex]的图像: 3Dfunc

scanf函数中的扫描集

ANSI C语言标准向scanf函数增加了一种新特性,叫做扫描集。利用此特性可以解决一些处理文本时的棘手问题。

最开始源于我对CSV(逗号分隔值)文件的处理。(本文不考虑CSV文件中引号和转义字符等其他特性)

例如下面这段代码

char a[100],b[100];
scanf("%s,%s",a,b);

如果用它读入下面的数据:

Alice,Bob

会直接把“Alice,Bob”赋值给a而继续等待输入b。

我在网上查了这种问题的解决方法,较为简便的一种就是利用扫描集。

继续阅读“scanf函数中的扫描集”

对C语言中不同类型数据计算速度的测试

我对C语言中各种数据类型的四则运算速度进行了测试。

操作系统:Windows 8.1 专业版 (64位)
编译器:GCC 4.8.1 64-bit Release (未开任何优化)
处理器:Intel Core i7-4702MQ

测试数据选择的都是12345和123

测试源程序:

继续阅读“对C语言中不同类型数据计算速度的测试”

从图片看出伪随机数的周期性

今天尝试用代码生成了一张大小为1024*1024,每个像素的RGB值都是随机数的图片(以下图片经过了一定程度的压缩):

random1

本应该是完全随机的图案,但是在图片中却可以明显地看出许多竖线,这显然是伪随机数的周期性导致的。

继续阅读“从图片看出伪随机数的周期性”

用编程来玩的游戏CodeCombat

今天发现了一个不错的网页游戏,名字叫CodeCombat。

在游戏中,你需要编写代码去控制人物完成一定的任务。刚开始的时候,游戏会引导你使用类似moveDown()这样的函数去移动,或者类似attack()这样的函数去攻击怪物。随着游戏的进行,你需要学会使用判断语句、循环语句来做更多的事情,也需要自己写代码获取距离、计算坐标。

继续阅读“用编程来玩的游戏CodeCombat”