C 语言实现独立样本 t 检验和配对样本 t 检验

源代码链接:https://github.com/Illusionna/tiny-stats/blob/main/t-test.c

cpp 复制代码
#include <math.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>


// Box-Muller Transform.
double random_normal(double mu, double sigma) {
    static double U;
    static double V;
    static int phase = 0;
    double Z;

    if (phase == 0) {
        U = (rand() + 1.0) / (RAND_MAX + 1.0);
        V = (rand() + 1.0) / (RAND_MAX + 1.0);
        Z = sqrt(-2.0 * log(U)) * sin(2.0 * M_PI * V);
    } else {
        Z = sqrt(-2.0 * log(U)) * cos(2.0 * M_PI * V);
    }
    phase = 1 - phase;

    return Z * sigma + mu;
}


double incbeta(double a, double b, double x) {
    static const double epsilon = 1.0e-30;
    static const double condition = 1.0e-8;

    if (x < 0.0 || x > 1.0) return INFINITY;
    if (x > (a + 1.0) / (a + b + 2.0)) return 1.0 - incbeta(b, a, 1.0 - x);

    double f = 1.0;
    double c = 1.0;
    double d = 0.0;
    const double lbeta_ab = lgamma(a) + lgamma(b) - lgamma(a + b);
    const double front = exp(a * log(x) + b * log(1.0 - x) - lbeta_ab) / a;

    for (int i = 0; i <= 200; ++i) {
        int m = i / 2;
        double numerator;

        if (i == 0) numerator = 1.0;
        else if (i % 2 == 0) numerator = (m * (b - m) * x) / ((a + 2.0 * m - 1.0) * (a + 2.0 * m));
        else numerator = - ((a + m) * (a + b + m) * x) / ((a + 2.0 * m) * (a + 2.0 * m + 1));

        d = 1.0 + numerator * d;
        if (fabs(d) < epsilon) d = epsilon;
        d = 1.0 / d;

        c = 1.0 + numerator / c;
        if (fabs(c) < epsilon) c = epsilon;

        double cd = c * d;
        f = f * cd;
        if (fabs(1.0 - cd) < condition) return front * (f - 1.0);
    }
    return INFINITY;
}


double cdf_student_t(double t, double df) {
    /*
    double x = df / (t * t + df);
    double p = 0.5 * incbeta(df / 2.0, 0.5, x);
    return (t > 0) ? (1.0 - p) : p;
    */
    if (df <= 0.0) return NAN;
    if (t == 0.0) return 0.5;
    double cache = sqrt(t * t + df);
    return incbeta(df / 2.0, df / 2.0, (t + cache) / (2.0 * cache));
}


double ttest_independent(double *group1, double *group2, int n1, int n2, int equal_var) {
    double sum1 = 0.0;
    double sum2 = 0.0;
    for (int i = 0; i < n1; ++i) sum1 = sum1 + group1[i];
    for (int i = 0; i < n2; ++i) sum2 = sum2 + group2[i];
    double mean1 = sum1 / n1;
    double mean2 = sum2 / n2;

    double var1 = 0.0;
    double var2 = 0.0;
    for (int i = 0; i < n1; ++i) var1 = var1 + (group1[i] - mean1) * (group1[i] - mean1);
    for (int i = 0; i < n2; ++i) var2 = var2 + (group2[i] - mean2) * (group2[i] - mean2);
    var1 = var1 / (n1 - 1);
    var2 = var2 / (n2 - 1);

    double t;
    double df;

    if (equal_var) {
        df = n1 + n2 - 2.0;
        double pooled_var = ((n1 - 1.0) * var1 + (n2 - 1.0) * var2) / df;
        t = (mean1 - mean2) / sqrt(pooled_var * (1.0 / n1 + 1.0 / n2));
    } else {
        double satterthwaite1 = var1 / n1;
        double satterthwaite2 = var2 / n2;
        t = (mean1 - mean2) / sqrt(satterthwaite1 + satterthwaite2);
        double numerator = (satterthwaite1 + satterthwaite2) * (satterthwaite1 + satterthwaite2);
        double denominator = (satterthwaite1 * satterthwaite1) / (n1 - 1.0) + (satterthwaite2 * satterthwaite2) / (n2 - 1.0);
        df = numerator / denominator;
    }

    double cdf = cdf_student_t(t, df);
    return 2.0 * (cdf > 0.5 ? 1.0 - cdf : cdf);
}


double ttest_paired(double *state1, double *state2, int n) {
    if (n < 2) return NAN;

    double sum_diff = 0.0;
    double sum_square_diff = 0.0;
    for (int i = 0; i < n; ++i) {
        double diff = state1[i] - state2[i];
        sum_diff = sum_diff + diff;
        sum_square_diff = sum_square_diff + diff * diff;
    }

    double mean_diff = sum_diff / n;
    double var_diff = (sum_square_diff - (sum_diff * sum_diff / n)) / (n - 1);
    double std_error = sqrt(var_diff / n);

    double t = mean_diff / std_error;
    double cdf = cdf_student_t(t, n - 1.0);
    double p = 2.0 * (cdf > 0.5 ? 1.0 - cdf : cdf);
    return p;
}



int main(int argc, char *argv[], char *envs[]) {
    double p;
    srand((unsigned int)time(NULL));

    int n1 = 6;
    int n2 = 4;
    double mu1 = 75.0;
    double mu2 = 82.0;
    double sigma1 = 8.0;
    double sigma2 = 8.0;

    double category1[n1];
    double category2[n2];

    for (int i = 0; i < n1; ++i) category1[i] = random_normal(mu1, sigma1);
    for (int i = 0; i < n2; ++i) category2[i] = random_normal(mu2, sigma2);
    p = ttest_independent(category1, category2, n1, n2, sigma1 == sigma2);
    printf("Independent Samples T-test:\x1b[32m p = %.12lf\x1b[0m\n", p);

    double before[] = {22, 20, 19, 24, 25, 25, 28, 22, 30, 27, 24, 18, 16, 19, 19, 28, 24, 25, 25, 23};
    double after[] = {24, 22, 19, 22, 28, 26, 28, 24, 30, 29, 25, 20, 17, 18, 18, 28, 26, 27, 27, 24};
    p = ttest_paired(before, after, sizeof(after) / sizeof(after[0]));
    printf("Paired Sample T-test:\x1b[32m p = %.12lf\x1b[0m\n", p);

    return 0;
}
相关推荐
J2虾虾20 小时前
C 语言 sizeof 完全用法指南
c语言·数据结构·算法
skywalk816320 小时前
段言的设计文档:中文编程赛道的竞争格局,谁在牌桌上?
开发语言·学习·编程
xxwxx__20 小时前
51单片机定时器/计数器中断详解(T0和T1)——从入门到精通
c语言·单片机·嵌入式硬件·51单片机
cft56200_ln20 小时前
TDA4时间同步3 网卡添加虚拟时间戳
c语言·开发语言·arm开发·驱动开发·嵌入式硬件·网络协议
1892280486121 小时前
NV091固态MT29F16T08EWLCHD8-QJES:C
c语言·开发语言
AI thought21 小时前
C语言企业项目实战(四)
c语言·单元测试·压力测试·企业项目·工程体系
AI科技星21 小时前
《数术工坊:无穷套娃录》 一部用数学套娃写成的“天书小说”
c语言·开发语言·网络·量子计算·agi
m0_5474866621 小时前
华南农业大学《C语言程序设计》期末试卷及答案2018-2025年PDF
c语言·开发语言·pdf·c语言程序设计
Hello:CodeWorld1 天前
C 风格变参 vs C++ 变参模板:核心区别与选型指南
c语言·c++·算法
十月的皮皮1 天前
C语言学习笔记20260606- 求月份天数三种写法
c语言·笔记·学习