【面试代码复盘】雾角科技

问题1

求任意浮点数的算术平方根,要求精度小于eps = 1e-6。

心路历程

自己写的一起合成,就是一个简单的二分,然后0-1之间的浮点数的求法也考虑了。面试官看了后让处理一下边界条件的情况,想了想没看出来是什么问题。

n = 0
l, r = 0, max(1, n)
eps = 1e-6
while l < r:
    mid = (l + r) / 2
    if abs(mid ** 2 - n) < eps:
        break
    if mid ** 2 - n > 0:
        r = mid
    else:
        l = mid
print(mid - n ** 0.5)
print(mid - n ** 0.5 < eps)

面试官提醒了一下,说让把 n = 0 的答案输出一下,并且看一下精度是否满足 eps。

输出看了一下答案,没满足精度

0.0009765625
False

想了想就是在while循环里边的break的判断有问题,应该是 abs(mid - n ** 0.5) < eps 就好了,但是在这里我们不能使用 n ** 0.5,面试的时候想了半天都没想到应该怎么解决,最后面试官提醒了一下才知道,还是刷题太少了。代码如下:

n = 0
l, r = 0, max(1, n)
eps = 1e-6
while l < r:
    mid = (l + r) / 2
    if r - l < eps:
        break
    if mid ** 2 - n > 0:
        r = mid
    else:
        l = mid
print(mid - n ** 0.5)
print(abs(mid - n ** 0.5) < eps)

输出为:

4.76837158203125e-07
True

问题2

给定一个圆,在当前圆中随机抽取一个点

心路历程

想的是分别按照 半径 和 角度 按照均匀分布做抽样,然后再按照 sin 和 cos 根据半径和圆心求出抽样的结果,然后就按照思路写了一下。

import random
import math
import matplotlib.pyplot as plt
import numpy as np


def plot_circle(center=(3, 3), r=2):
    x = np.linspace(center[0] - r, center[0] + r, 5000)
    y1 = np.sqrt(r ** 2 - (x - center[0]) ** 2) + center[1]
    y2 = -np.sqrt(r ** 2 - (x - center[0]) ** 2) + center[1]
    plt.plot(x, y1, c='k')
    plt.plot(x, y2, c='k')


r = 1
x, y = 1, 1
draw_ans = [[], []]
point_numbers = 5000
for _ in range(5000):
    t1 = random.uniform(0, r)
    t2 = random.uniform(0, math.pi * 2)
    yy = t1 * math.sin(t2) + x
    xx = t1 * math.cos(t2) + y
    draw_ans[0].append(xx)
    draw_ans[1].append(yy)
plot_circle((x, y), r)
plt.scatter(draw_ans[0], draw_ans[1])  # x 代表x轴 y 代表y轴数据, 数据维度必须相同
plt.show()

res = 0
R = math.sqrt(r * r / 2)
for i in range(len(draw_ans[0])):
    if (draw_ans[0][i] - x) ** 2 + (draw_ans[1][i] - y) ** 2 <= R * R:
        res += 1
print(res/point_numbers)

面试官看了之后说这样的抽取并不是均匀的,然后让可视化出来,发现更靠近圆心地方的点更加的密集。

随后我又尝试输出了一下整个圆面积一半的同心圆内落入的点的数量占比,就是上边代码的最后几行,发现结果为 0.71,并不是0.5,所以这样子的随机抽样是不对的。

想了想不知道怎么搞,然后面试官提醒,可以将整个圆分成很多个同心圆,让相邻的圆的面积的差相等,然后在每个圆中在做抽样,有了思路然后实现,代码如下:

import random
import math
import matplotlib.pyplot as plt
import numpy as np


def plot_circle(center=(3, 3), r=2):
    x = np.linspace(center[0] - r, center[0] + r, 5000)
    y1 = np.sqrt(r ** 2 - (x - center[0]) ** 2) + center[1]
    y2 = -np.sqrt(r ** 2 - (x - center[0]) ** 2) + center[1]
    plt.plot(x, y1, c='k')
    plt.plot(x, y2, c='k')


r = 1
x, y = 1, 1
k = 100
r1 = math.sqrt(r * r / k)
r_list = [0, r1]
for i in range(2, k + 1):
    r_list.append(r1 * math.sqrt(i))
kth = random.randint(0, k - 1)
t1 = random.uniform(r_list[kth], r_list[kth + 1])
t2 = random.uniform(0, math.pi * 2)
yy = t1 * math.sin(t2) + x
xx = t1 * math.cos(t2) + y
print(xx, yy)


draw_ans = [[], []]
point_numbers = 10000
for _ in range(point_numbers):
    kth = random.randint(0, k - 1)
    t1 = random.uniform(r_list[kth], r_list[kth + 1])
    t2 = random.uniform(0, math.pi * 2)
    yy = t1 * math.sin(t2) + x
    xx = t1 * math.cos(t2) + y
    draw_ans[0].append(xx)
    draw_ans[1].append(yy)
plot_circle((x, y), r)
plt.scatter(draw_ans[0], draw_ans[1])  # x 代表x轴 y 代表y轴数据, 数据维度必须相同
plt.show()

res = 0
R = math.sqrt(r * r / 2)
for i in range(len(draw_ans[0])):
    if (draw_ans[0][i] - x) ** 2 + (draw_ans[1][i] - y) ** 2 <= R * R:
        res += 1
print(res/point_numbers)

上述代码是将整个圆分成了一百个同心圆然后再做的抽样。

 随后我又尝试输出了一下整个圆面积一半的同心圆内落入的点的数量占比,就是上边代码的最后几行,发现结果为 0.5。

然后面试官又说了,现在的实现还是近似的,能不能直接给出抽样的结果。想了一会儿不知道怎么搞(我是真的菜

然后面试官提醒,将k看作无穷大,然后再想想。

r_list 变成了 r * \sqrt{\frac{i}{k}},所以对半径做抽样的时候就直接可以写成 math.sqrt(random.uniform(0, 1)) * r 即可,所以最后的代码如下:

import random
import math
import matplotlib.pyplot as plt
import numpy as np


def plot_circle(center=(3, 3), r=2):
    x = np.linspace(center[0] - r, center[0] + r, 5000)
    y1 = np.sqrt(r ** 2 - (x - center[0]) ** 2) + center[1]
    y2 = -np.sqrt(r ** 2 - (x - center[0]) ** 2) + center[1]
    plt.plot(x, y1, c='k')
    plt.plot(x, y2, c='k')


r = 1
x, y = 1, 1
t1 = math.sqrt(random.uniform(0, 1)) * r
t2 = random.uniform(0, math.pi * 2)
yy = t1 * math.sin(t2) + x
xx = t1 * math.cos(t2) + y
print(xx, yy)

draw_ans = [[], []]
point_numbers = 10000
for _ in range(point_numbers):
    t1 = math.sqrt(random.uniform(0, 1)) * r
    t2 = random.uniform(0, math.pi * 2)
    yy = t1 * math.sin(t2) + x
    xx = t1 * math.cos(t2) + y
    draw_ans[0].append(xx)
    draw_ans[1].append(yy)
plot_circle((x, y), r)
plt.scatter(draw_ans[0], draw_ans[1])
plt.show()
res = 0
R = math.sqrt(r * r / 2)
for i in range(len(draw_ans[0])):
    if (draw_ans[0][i] - x) ** 2 + (draw_ans[1][i] - y) ** 2 <= R * R:
        res += 1
print(res/point_numbers)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值