首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C語言控制台繪圖:以星號繪製正弦/餘弦曲線完整指南

     編輯:關於C語言

前言

在無圖形庫的純文字控制台環境中,利用字元矩陣近似繪製數學函數曲線,是經典的程式設計練習。本文詳細解析兩種繪製餘弦曲線與兩種繪製正弦曲線的演算法,涵蓋反三角函數定域、座標映射、對稱性利用與週期性延伸等核心技巧。

座標系統與縮放策略

  • 水平軸:對應角度/弧度定域,通常映射為 0~62 字元寬(63 列)。
  • 垂直軸:對應函數值範圍 [-1, 1],映射為行數,每行代表 0.1 步長。
  • 縮放因子:acos(x) 或 asin(x) 回傳 [0, π],乘 10 後取整得到 0~31 範圍,再對稱擴展至 0~62。

餘弦曲線四種實作

方法一:模擬法(雙星號對稱)

for (i = 1.0; i >= -0.4; i -= 0.1) {      // 垂直掃描,從 1 降至 -0.4
    j = (int)(acos(i) * 10);                // 左側星號欄位
    for (k = 0; k < j; k++) putchar(' ');
    putchar('*');
    for (; k < 62 - j; k++) putchar(' ');   // 中間空白
    putchar('*');                           // 右側對稱星號
    putchar('\n');
}

特點:直接利用 acos 定義域 [-1,1] 對應 [π,0],垂直掃描列印雙側曲線。

方法二:對稱性單迴圈判斷

for (i = 1.0; i >= -1.0; i -= 0.1) {
    k = (int)(acos(i) * 10);
    for (j = 0; j < 62; j++) {
        if (j == k || j == 62 - k) putchar('*');
        else putchar(' ');
    }
    putchar('\n');
}

優點:單一水平掃描迴圈,邏輯清晰,易擴展多曲線疊加。

正弦曲線四種實作

方法一:分段垂直掃描(正負定域分開)

// 正半週:asin 定義域 [0,1] → [0, π/2]
for (i = 1.0; i > 0.0; i -= 0.1) {
    k = (int)(asin(i) * 10);
    for (j = 0; j < k; j++) putchar(' ');
    putchar('*');
    for (; j < 31 - k; j++) putchar(' ');
    putchar('*');
    putchar('\n');
}
// 負半週:asin 定義域 [0,-1] → [0, -π/2],需平移 33 格
for (i = 0.0; i >= -1.0; i -= 0.1) {
    k = (int)(asin(i) * 10);  // k 為負或零
    for (j = 0; j < k + 33; j++) putchar(' ');
    putchar('*');
    for (; j < 62 - k; j++) putchar(' ');
    putchar('*');
    putchar('\n');
}

關鍵:負半週星號位置須整體右移半個週期(31 格)再加上對稱偏移。

方法二:對稱性與週期性單迴圈

for (i = 1.0; i >= -1.0; i -= 0.1) {
    k = (int)(asin(i) * 10);          // k ∈ [-15, 15] 約略
    for (j = 0; j <= 62; j++) {
        // 三個對稱點:原點、水平鏡像、半週期平移
        if (j == k || j == 62 + k || j == 31 - k)
            putchar('*');
        else
            putchar(' ');
    }
    putchar('\n');
}

數學依據:sin(θ) = sin(π-θ)(水平對稱),sin(θ+π) = -sin(θ)(半週期翻轉)。三條件涵蓋一個完整週期的所有極值點。

完整可執行範例(含雙曲線疊加)

#include <stdio.h>
#include <math.h>

#define WIDTH 62
#define STEP 0.1

void draw_cosine(void) {
    puts("=== Cosine Curve ===");
    for (double y = 1.0; y >= -1.0; y -= STEP) {
        int k = (int)(acos(y) * 10);
        for (int x = 0; x <= WIDTH; ++x) {
            putchar((x == k || x == WIDTH - k) ? '*' : ' ');
        }
        putchar('\n');
    }
}

void draw_sine(void) {
    puts("\n=== Sine Curve ===");
    for (double y = 1.0; y >= -1.0; y -= STEP) {
        int k = (int)(asin(y) * 10);
        for (int x = 0; x <= WIDTH; ++x) {
            putchar((x == k || x == WIDTH + k || x == WIDTH/2 - k) ? '*' : ' ');
        }
        putchar('\n');
    }
}

int main(void) {
    draw_cosine();
    draw_sine();
    return 0;
}

進階優化與擴展

需求實作策略
平滑度提升減小 STEP 至 0.05,WIDTH 擴至 120,配合 ANSI 捲動
多函數疊加建立字元緩衝區 char buf[H][W],合成後一次列印
座標軸與刻度預先在緩衝區繪製 X/Y 軸、標註關鍵角度 (0, π/2, π...)
動畫效果配合 usleep + printf("\033[H") 刷新畫面
高精度繪圖改用 Bresenham 演算法在字元格內插值,減少鋸齒

常見錯誤與除錯

  1. 定義域溢位:acos/asin 引數必須在 [-1,1],迴圈邊界嚴格控制,避免浮點誤差導致 NaN。
  2. 整數截斷誤差:(int)(acos(y)*10) 向零取整,關鍵點可能偏移 1 格,可改用 lround 四捨五入。
  3. 負索引存取:方法二中 62 + k 若 k 為負可能小於 0,需加邊界檢查 if (idx >= 0 && idx <= WIDTH)。

教學價值總結

這些範例雖屬「玩具程式」,卻濃縮了:

  • 數學函數定義域/值域與離散座標映射
  • 對稱性、週期性減少重複運算
  • 巢狀迴圈與條件判斷的像素級控制
  • 浮點精度與整數截斷的工程取捨

建議讀者以此為基礎,嘗試繪製 tan(x)、e^-x sin(x) 阻尼震盪、李薩茹曲線等進階圖形,並嘗試移植至 SDL/OpenGL 進行像素級真實繪圖對比。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved