按下 Manage 按鈕 Settings, 輸入 server, 儘量避免選項被啟用, 讓選項儘量 disable 或 off 例如:
Http: Proxy Strict SSL 不要勾選
C_Cpp: Code Folding 選擇 disable
C_Cpp: Suggest Snippets 不要勾選
按下 Manage 按鈕 Settings, 輸入 server, 儘量避免選項被啟用, 讓選項儘量 disable 或 off 例如:
Http: Proxy Strict SSL 不要勾選
C_Cpp: Code Folding 選擇 disable
C_Cpp: Suggest Snippets 不要勾選
// sudo apt install libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev
// g++ sdldraw.cpp -lSDL2 -lSDL2_image -lSDL2_ttf && ./a.out
// sdldraw.cpp
#include <unistd.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
void drawcircle(SDL_Renderer *renderer, float cx, float cy, float r) {
const int max_segments = 32;// large enough to smooth circle
const double d_theta = M_PI * 2 / max_segments;
double theta = d_theta;// 2nd θ
int px = cx + r;// 1st θ = 0
int py = cy;
int lines = max_segments - 1;// lines to draw
while (lines -- > 0) {
int nx = cx + r*cosf(theta);
int ny = cy + r*sinf(theta);
SDL_RenderDrawLine(renderer, px, py, nx , ny);
theta += d_theta;// next θ
px = nx;
py = ny;
}
SDL_RenderDrawLine(renderer, px, py, cx + r , cy);// close loop
}
int main(int argc, char** argv) {
if (SDL_Init(SDL_INIT_EVERYTHING) == 0) {
SDL_Window *xwin = SDL_CreateWindow("繪圖程式", 0, 0, 800, 600, SDL_WINDOW_RESIZABLE);
if (xwin) {
SDL_Renderer *renderer = SDL_CreateRenderer(xwin, -1, SDL_RENDERER_ACCELERATED);
if (renderer) {
SDL_Texture *bgPicture = IMG_LoadTexture(renderer, "snap.jpg");
SDL_RenderCopy(renderer, bgPicture, NULL, NULL);
SDL_RenderPresent(renderer);// show current image
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
const char *message = "準心";
const SDL_Color colorGreen = {.r=0, .g=255, .b=0, .a=255};
TTF_Font *ukai = (TTF_Init() == 0) ? TTF_OpenFont("./fonts/ukai.ttc", 32) : nullptr;
SDL_Rect target_cross;
SDL_Surface *msgSurface = ukai ? TTF_RenderUTF8_Blended(ukai, message, colorGreen) : nullptr;
SDL_Texture *msgTexture = SDL_CreateTextureFromSurface(renderer, msgSurface);
int &radius = target_cross.w; // alias
if (msgSurface) {
target_cross.w = msgSurface->w;
target_cross.h = msgSurface->h;
SDL_FreeSurface(msgSurface);
}
SDL_Event event;
while (true) { // event loop begin
usleep(1000);
SDL_PollEvent(&event);
if (event.type == SDL_QUIT) break;
if (event.type == SDL_MOUSEBUTTONDOWN) {
if (event.button.button == SDL_BUTTON_LEFT) {
SDL_RenderCopy(renderer, bgPicture, NULL, NULL);
int px = event.button.x;
int py = event.button.y;
if (msgTexture) {
target_cross.x = px - target_cross.w/2;
target_cross.y = py - target_cross.h/2;
drawcircle(renderer, px, py, radius);// green circle
SDL_RenderDrawLine(renderer, px, py - radius, px, py + radius);// red cross
SDL_RenderDrawLine(renderer, px - radius, py, px + radius, py);
SDL_RenderCopy(renderer, msgTexture, NULL, &target_cross);
}
SDL_RenderPresent(renderer);
printf("Left mouse is down @(%d,%d)\n", px, py);
}
} else if (event.type == SDL_WINDOWEVENT) {
if (event.window.event == SDL_WINDOWEVENT_RESIZED) {
SDL_RenderCopy(renderer, bgPicture, NULL, NULL);
SDL_RenderPresent(renderer);
}
}
}
if (bgPicture) SDL_DestroyTexture(bgPicture);
if (msgTexture) SDL_DestroyTexture(msgTexture);
if (ukai) TTF_CloseFont(ukai);
SDL_DestroyRenderer(renderer);
}
SDL_DestroyWindow(xwin);
TTF_Quit();
}
SDL_Quit();
}
return 0;
}
後記. 2025.07.29 改用 sdl3, 程式庫事先要從原始碼編譯並安裝, 上述程式修改並重新編譯:
// g++ sdl3draw.cpp -lSDL3 -lSDL3_image -lSDL3_ttf && ./a.out
// sdl3draw.cpp
#include <stdio.h>
#include <unistd.h>
#include <math.h>
#include <SDL3/SDL.h>
#include <SDL3_image/SDL_image.h>
#include <SDL3_ttf/SDL_ttf.h>
void drawcircle(SDL_Renderer *renderer, float cx, float cy, float r) {
const int max_segments = 32;
const double d_theta = M_PI * 2 / max_segments;
double theta = d_theta;
int px = cx + r;
int py = cy;
int lines = max_segments - 1;
while (lines -- > 0) {
int nx = cx + r*cosf(theta);
int ny = cy + r*sinf(theta);
SDL_RenderLine(renderer, px, py, nx , ny);
theta += d_theta;
px = nx;
py = ny;
}
SDL_RenderLine(renderer, px, py, cx + r , cy);// close loop
}
int main(int argc, char** argv) {
if (SDL_Init(SDL_INIT_EVENTS)) {
SDL_Window *xwin = SDL_CreateWindow("繪圖程式", 800, 600, SDL_WINDOW_RESIZABLE);
if (xwin) {
SDL_Renderer *renderer = SDL_CreateRenderer(xwin, nullptr);
if (renderer) {
SDL_Texture *bgPicture = IMG_LoadTexture(renderer, "snap.jpg");
SDL_RenderTexture(renderer, bgPicture, NULL, NULL);
SDL_RenderPresent(renderer);
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
const char *message = "準心";
const SDL_Color colorGreen = {.r=0, .g=255, .b=0, .a=255};
TTF_Font *ukai = (TTF_Init()) ? TTF_OpenFont("./fonts/ukai.ttc", 32) : nullptr;
SDL_FRect target_cross;
SDL_Surface *msgSurface = ukai ? TTF_RenderText_Blended(ukai, message, 0, colorGreen) : nullptr;
SDL_Texture *msgTexture = SDL_CreateTextureFromSurface(renderer, msgSurface);
float &radius = target_cross.w; // alias
if (msgSurface) {
target_cross.w = msgSurface->w;
target_cross.h = msgSurface->h;
SDL_DestroySurface(msgSurface);
}
SDL_Event event;
while (true) {
usleep(1000);
SDL_PollEvent(&event);
if (event.type == SDL_EVENT_QUIT) break;
if (event.type == SDL_EVENT_MOUSE_BUTTON_DOWN) {
if (event.button.button == SDL_BUTTON_LEFT) {
SDL_RenderTexture(renderer, bgPicture, NULL, NULL);
int px = event.button.x;
int py = event.button.y;
if (msgTexture) {
target_cross.x = px - target_cross.w/2;
target_cross.y = py - target_cross.h/2;
drawcircle(renderer, px, py, radius);// green circle
SDL_RenderLine(renderer, px, py - radius, px, py + radius);// red cross
SDL_RenderLine(renderer, px - radius, py, px + radius, py);
SDL_RenderTexture(renderer, msgTexture, NULL, &target_cross);
}
SDL_RenderPresent(renderer);
printf("Left mouse is down @(%d,%d)\n", px, py);
}
} else if (event.window.type == SDL_EVENT_WINDOW_RESIZED) {
SDL_RenderTexture(renderer, bgPicture, NULL, NULL);
SDL_RenderPresent(renderer);
}
}
if (bgPicture) SDL_DestroyTexture(bgPicture);
if (msgTexture) SDL_DestroyTexture(msgTexture);
if (ukai) TTF_CloseFont(ukai);
SDL_DestroyRenderer(renderer);
}
SDL_DestroyWindow(xwin);
TTF_Quit();
}
SDL_Quit();
}
return 0;
}
import multiprocessing as mp
import time
def iso_task(k):
print(f"task {k} @{time.time()} sec: sleep for 1 second")
time.sleep(1)
print(f"task {k} @{time.time()} sec: finish.")
n = mp.cpu_count()
print(f"Total CPUs = {n}")
tasks = []
start_time = time.time()
for i in range(n): # prepare all tasks to run
task = mp.Process(target=iso_task, args=(i,))
tasks.append(task)
for i in range(n): # fire all tasks at the same time
tasks[i].start()
for i in range(n): # wait all tasks to finish
tasks[i].join()
dt = time.time() - start_time
print(f"{round(dt, 3)} sec elapsed")
不囉唆, 詳如以下代碼:
import numpy as np
def Cp(x, n): # 快速疊代法, 計算 1st kind Chebyshev 多項式
if (n == 0):
return 1
if (n == 1):
return x
pk_1 = 1
pn_1 = x
k = 1
while k < n :
pk = pn_1 * x * 2 - pk_1
pk_1 = pn_1
pn_1 = pk
k += 1
return pn_1
test_f = lambda x: np.exp(-x*x) # 測試函式
Ln = 20
px = [0.0] * Ln
py = [0.0] * Ln
theta = [0.0] * Ln
for k in range(Ln) :
theta[k] = np.pi * (k + 0.5) / Ln;# θₖ = np.pi * (k + 0.5) / Ln
px[k] = np.cos(theta[k]);# pxₖ = cos(θₖ)
py[k] = test_f(px[k]);# pyₖ = f(pxₖ) to be used in Chebyshev Interpolation
def Ci(i): # Coefficient, bind with pyₖ, θₖ, Ln
sum = 0
for k in range(Ln) :
sum += py[k] * np.cos(i * theta[k])
return sum * 2 / Ln # 2/n * Σₙf(pxₖ)*Tₖ(pxₖ), k = 0, 2, ... n - 1
def Chebyshev_interpolation(t): # Chebyshev Interpolation Polynomials
sum = Ci(0) / 2;# Σₙ Cₖ*Tₖ(x) - C₀/2 = Σₖ Cₖ*Tₖ(x) + C₀/2, k = 1, 2, ... n-1, C₀*T₀(x) = C₀
k = 1
while k < Ln :
sum += Ci(k) * Cp(t, k)
k += 1
return sum
for k in range(Ln) :
xk = px[k] + 0.1
c = test_f(xk) # 實際值
h = Chebyshev_interpolation(xk)# Chebyshev 合成值
print(f"x={xk}, 內插={h}, 實際值={c}, 誤差 = {h-c}")
看了一些文章後, 自己手動寫了一些簡單的程式, 實現各種定積分的方式
import numpy as np
def Lp(x, n) : # evaluate order n-1 Legendre polynomials at x
if (n == 0) :
return 1.0
if (n == 1) :
return x
pn_1, pk_1 = x, 1.0 # 疊代初始化, 因為 n > 1, 所以至少疊代一次
k = 1 # 此刻從 k 開始, 直到 n - 1
while k < n :
pn_1, pk_1 = (pn_1*x*(2 * k + 1) - pk_1*k) / (k + 1), pn_1
k += 1 # # 因為 k=n-1 所以 n=k+1, 2*n-1 = 2*(k+1)-1 = 2*k+1
return pn_1 # (Lp(x, k)*x*(2*n-1) - Lp(x, k-1)*k) / n, k = n - 1
def d_Lp(x, n) : # derivative of order n-1 Legendre Polynomials at x
if (n == 0) :
return 0.0
if (n == 1) :
return 1.0;# LP′ₙ(x) = (−LPₙ(x)*x + LPₖ(x)) * n / (1−x*x), k=n-1
return (Lp(x, n - 1) - Lp(x, n) * x) * n / (1.0 - x*x)
# Multiple root finder algorithm for Legendre polynomial: https://publikacio.uni-eszterhazy.hu/3009/1/AMI_33_from3to13.pdf
def by_newton(f, a=1.0, b=2.0, n=10):
def newton_raphson(n, eps=1e-16): # using: xₖ = xₖ - f(xₖ) / [f'(xₖ) - f(xₖ) Σₖ 1/(xₖ - xᵢ)]
e = np.cos(np.array([np.pi*(k + 0.5)/n for k in range(n)])) #initial guess
for k in range(n) : # find all roots by newton raphson method
xk = e[k]
iteration = 0
while (iteration < 1000) :
iteration += 1
f = Lp(xk, n)
temp = f if (f > 0) else -f
if (temp < eps): # 收斂
break
sum_r = 0.0
for j in range(k) :# sum_r = Σₖ 1/(xₖ - xᵢ) to remove previouse root
delta = xk - e[j]
temp = delta if (delta < 0) else -delta
if (temp < eps) :
continue# skip singular value!
sum_r += 1.0 / delta
dx = f / (d_Lp(xk, n) - f * sum_r)
temp = dx if (dx > 0) else -dx
if (temp < eps) : # 收斂
break
xk -= dx # xₖ = xₖ - f(xₖ) / [f'(xₖ) - f(xₖ) Σₖ 1/(xₖ - xᵢ)]
e[k] = xk # final root update
xi = [e]
derivative = d_Lp(xi[0], n)
xi.append(2 / (derivative*derivative*(1 - xi[0]*xi[0])))
return np.array(xi)
xw = newton_raphson(n)
scale = (b - a) / 2.0 # linear transform tx: bias + scale * 1 = b => scale = (b - a) / 2
bias = (b + a) / 2.0 # linear transform tx: bias + scale *(-1) = a => bias = (b + a) / 2
tx = xw[0] * scale + bias # x -> tx
sum = f(tx).dot(xw[1])
return sum * scale
def by_jacobi(f, a=1.0, b=2.0, n=10):
def Jacobi_method(n, eps=1e-16): # using: xₖ = xₖ - f(xₖ) / [f'(xₖ) - f(xₖ) Σₖ 1/(xₖ - xᵢ)]
J = np.zeros((n, n))
d = len(J) - 1 # to fill into the jacobian tridiagonal matrix, trace = 0, and it is a symmetry matrix
for k in range(d): # fill
m = k + 1
J[k][m] = m / np.sqrt(4.0 * m * m - 1.0)
J[m][k] = J[k][m]
e = np.linalg.eigvals(J) # nxn jacobi matrix, solve eigenvalues
xi = [np.sort(e)] # eigenvalue is same as root of the order n-1 Legendre polynopmial
derivative = d_Lp(xi[0], n)
xi.append(2 / (derivative*derivative*(1 - xi[0]*xi[0])))# weight relative eigenvalue
return np.array(xi)
xw = Jacobi_method(n)
scale = (b - a) / 2.0 # linear transform tx: bias + scale * 1 = b => scale = (b - a) / 2
bias = (b + a) / 2.0 # linear transform tx: bias + scale *(-1) = a => bias = (b + a) / 2
tx = xw[0] * scale + bias # x -> tx
sum = f(tx).dot(xw[1])
return sum * scale
def by_trapezoid(f, a=1.0, b=2.0, n=50): # integral with the trapezoid method, 使用 梯形面積=(上底 + 下底)/2 積分
x = np.linspace(a, b, n) # total n pints include a, b
y = f(x) # total n
n -= 1 # split to n - 1 interval
delta_x = (b - a) / n
sum = y[1:n].sum() + (y[0] + y[n]) / 2.0
return sum * delta_x
def by_simpson(f, a=1.0, b=2.0, n=50): # (b-a)/3 Σ[f(a) + 4f(a+h) + 2f(a + h) + 4f(a+2h) + 2f(a+3h) ... + f(b)]
if n % 2 == 1:
n += 1
dx = (b - a) / n
ddx = dx + dx # double dx
x4 = a + dx # 2nd term * 4
x2 = a + ddx # 3rd term * 2
sum = f(a) + f(b) # head + tail
for i in range(1, n - 2, 2) : # exclude head and tail
sum += f(x4) * 4 + f(x2) * 2
x4 += ddx # next
x2 += ddx # next
sum += f(x4) * 4 # last one
return sum * dx / 3
f = lambda x: np.exp(-x**2)
a = 0.0
b = 10.0
n = 15
anser = np.sqrt(np.pi) / 2
jacobi = by_jacobi(f, a, b, n)
newton = by_newton(f, a, b, n)
trapezoid = by_trapezoid(f, a, b, n)
simpson = by_simpson(f, a, b, n)
print(f"∫ :\tjacobi={jacobi} \t, newton={newton} \t, trapezoid={trapezoid}\t, simpson={simpson}\t, compare to {anser}")
print(f"Δ :\t {jacobi - anser} \t, {newton - anser}\t, {trapezoid - anser} \t, {simpson - anser}")
x-y 平面上, 相異 2 點 (xₖ, yₖ), k = 0, 1 可以畫成 一條直線(也可以看成是一次多項式 y = a₀ + a₁x), 相異3點不在同一條直線上就可以形成一個拋物線(可以看成是二次多項式 y= a₀ + a₁x + a₂x²), 相異 4 點但不在同一條拋物線上則能形成一個三次曲線(可以看成是三次多項式 y = a₀ + a₁x + a₂x² + a₃x³) , 以此類推, 相異 n 點就可以形成一個 n-1 次曲線, 或者說是 n-1 次多項式 y = Σₙ aₖxᵏ, k = 0 , 1 ,2 , ..., n-1 .數學上有個著名的 Lagrange Interpolation Polynomials, 網上翻譯成"拉格朗日內插多項式", 實際上就是利用 n 點的座標, 推算出該 n-1 次的多項式, 內插產生任何一點的函數值, 這個合成的插值多項式實際上等同原始多項式. 它與原始多項式不偏不移, 不折不扣, 一模一樣(數學上稱為 exact), 只是表達方式不同 f(t) = Σₙ aₖtᵏ, 這裡列出Lagrange Interpolation Polynomials 的另類表達式, 假設 (xₖ, yₖ) 是已知的座標點共有 n 個 {x₀, y₀, x₁, y₁, x₂, y₂, ..., xₖ, yₖ} , 則 :
f(t) = Σₙⱼ [yⱼ * Πₙₖ(t - xₖ)/(xⱼ - xₖ)] 其中 j != k, k = 0, 1, ,2, ..., n-1, j = 0, 1, 2,..., n-1
上面式子中 Σₙ 是 n 項總和, Πₙ 是 n 項總乘積, 我們只要將 t 用 xₖ 帶進去, 就會得到 f(t) = f(xₖ) = yₖ, 就能體會它就是原始多項式無誤, 用這個表達式用意是不需用矩陣運算求出係數 aₖ, 也能推斷出函數多項式的任一點函數值, 其實如果將整個 Lagrange Interpolation Polynomials 仔細展開就可以看出 aₖ 等於是 {x₀, y₀, x₁, y₁, x₂, y₂, ..., xₖ, yₖ} 所組成的函數值, 而 {x₀, y₀, x₁, y₁, x₂, y₂, ..., xₖ, yₖ} 都是已知的常數. 可以參考文章:
https://math.libretexts.org/Courses/Angelo_State_University/Mathematical_Computing_with_Python/3%3A_Interpolation_and_Curve_Fitting/3.2%3A_Polynomial_Interpolation
底下用 c++ 驗證一下結果:
#include<stdio.h>
double Lip(double *x, double *y, int n, double t) {// Lagrange Interpolation Polynomials
auto L = [x, n](int j, double t){
double pi = 1.0;
for (int k = 0; k < n; k ++) {// exclude (x[j] - x[k]) term
if (k == j) continue;
pi *= (t - x[k]) / (x[j] - x[k]);
}
return pi;
};
double f = 0;
for(int j = 0; j < n; j ++) { // Lip(t) = Σₙ (yⱼ * Lⱼ(t)), j = 0, 1, 2, ..., n-1
f += y[j] * L(j, t);
}
return f;
} // f(t) = Σₙ [yⱼ * Πₙ(t - xₖ)/(xⱼ - xₖ)], k = 0, 1, 2, ..., n-1
double *polynomials(double *x, int n) { // order n-1 polynomials
double *f = new double[n]();
for (int i = 0; i < n; i ++) {// f(x) = 1 + x + x^2
f[i] = 2 * x[i];// + x[i] * x[i];
}
return f;
}
int main() {
double x[3] = {1, 2, 3};
int n = sizeof(x)/sizeof(double);
double *y = polynomials(x, n);
printf("ans = %f\n", Lip(x, y, n, 1.2)); // interpolation at x = 1.2
delete [] y;
return 0;
}
from autograd import elementwise_grad as grad
from autograd.extend import defvjp, primitive
import numpy as np
# 定義函式原型, 輸入資料型態必須是 np.array(.) 才能在 autograd 內運算
@primitive
def polynomial_f(x): # primitive 只能用 def, 不能用 lambda, 用來定義 forward function
return x**3 # x³
# defvjp(polynomial_f, lambda o, x : (lambda g: 3*x**2))
#定義微分的 backward function, 需要將矩陣乘上微分方程
def grad_f(o, x): # 可以直接回傳 lambda, o 是 f(x) 的輸出, x 是 f(x) 輸入
def derivative(_): # 綁定 x
return 3*x**2
# return np.full(x.shape, _) * 3*x**2 # 綁定 x, _
return derivative
defvjp(polynomial_f, grad_f) # 將原型與微分方程綁定, 兜在一起
# 呼叫 autograd 的 grad function, 定義 n 階微分方程(order-n derivative): f'ⁿ(x) = dⁿf(x)/dx
df_n = lambda f, n = 1: df_n(grad(f), n - 1) if n > 1 else grad(f)
x = np.array([1, 2, 3, 4, 5]) # 測試 x 座標點, x 當成一組向量
print(f"f(x) = x³ : {polynomial_f(x)},\tx = {x}") # f(x) = x³
print(f"f'(x) = 3x² : {df_n(polynomial_f)(x) },\tx = {x}") # f(x) 1 階微分f'(x) = 3x²
print(f"f²'(x) = 6x : {df_n(polynomial_f, 2)(x)},\tx = {x}") # f(x) 2 階微分f"(x) = 6x
print(f"f³'(x) = 6 : {df_n(polynomial_f, 3)(x)},\tx = {x}") # f(x) 3 階微分f"'(x) = 6
print(f"f⁴'(x) = 0 : {df_n(polynomial_f, 4)(x)},\tx = {x}") # f(x) 4 階微分f""(x) = 0
按下 Manage 按鈕 Settings, 輸入 server, 儘量避免選項被啟用, 讓選項儘量 disable 或 off 例如: Http: Proxy Strict SSL 不要勾選 C_Cpp: Code Folding 選擇 disable C_Cpp: Sug...