保存时间:2026/4/2 11:10:25
| 品牌 | 型号 | 最低端配置 | 价格 |
|---|---|---|---|
| 新华三 | Unicube 灵犀 Cube | / | 14.99 万起 |
| 百度智能云 | 百舸 DeepSeek 一体机 | 8 卡昆仑芯 P800、双路多核 CPU、216TB 硬盘 | / |
| 百度智能云 | 千帆 DeepSeek 一体机 | 昆仑芯 P800(OAM 版或 PCIe 版)、昇腾 Atlas800 版可选 | / |
| 苏州创云 | DeepSeek 优智推理一体机 | 探索版,参数量 14B | 9.99 万起 |
| 苏州济丰寰亚 | DeepSeek 推理一体机 | 基础版,龙芯 3C5000 处理器、太初元碁 T100 加速卡 | 9.9 万起 |
| 易点云 | DeepSeek 一体机 | / | 13.99 万起 |
| 类型 | 总位数 | 符号位 | 指数位 | 小数位 | 是否为 IEEE 754 标准 |
|---|---|---|---|---|---|
| FP16 | 16 | 1 | 5 | 10 | 是 |
| FP32 | 32 | 1 | 8 | 23 | 是 |
| FP64 | 64 | 1 | 11 | 52 | 是 |
| FP8 | 通常 8 | 1 | 3 或 4 | 4 或 3 | 否,有不同的自定义标准 |
| TF32 | 32 | 1 | 8 | 23(与 FP32 类似,但指数范围不同) | 否 |
| BF16 | 32 | 1 | 8 | 16 | 否 |
0011 1110 1000,由于 FP16 的指数位为 5 位,尾数位为 10 位,这里指数部分为00111(表示 3),尾数部分为11101000,加上隐含的整数位 1,得到尾数为1.11101,根据浮点数计算公式,其值为(−1)0×1.11101×23−15=1.11101×2−12,转换为十进制约为 0.000238。0011 1110 1001,指数为00111,尾数为11101001,值为(−1)0×1.11101001×2−12,约为 0.000239。差值约为 0.000001。0111 1101 0000,指数为01111(表示 15),尾数为1010000,值为(−1)0×1.101×215−15=1.101,即 1.625。0111 1101 0001,指数为01111,尾数为1010001,值为(−1)0×1.1010001×20=1.626。差值约为 0.001。1011 1011 1000,指数为10111(表示 23),尾数为0111000,值为(−1)0×1.0111×223−15=296。1011 1011 1001,指数为10111,尾数为0111001,值为(−1)0×1.0111001×28=296.5。差值为 0.5。1111 1010 0000,指数为11111(表示 31),尾数为0100000,值为(−1)0×1.01×231−15=131072。1111 1010 0001,指数为11111,尾数为0100001,值为(−1)0×1.0100001×216=131072.5。差值为 0.5。1001 1100 0100 0000,这里超出了 FP16 的表示范围,会发生溢出,通常会被表示为无穷大(Inf)。| 整数 | 对应的 FP16 值 | 与下一个整数对应 FP16 的差值 |
|---|---|---|
| 1000 | 约 0.000238 | 约 0.000001 |
| 1001 | 约 0.000239 | - |
| 2000 | 1.625 | 0.001 |
| 2001 | 1.626 | - |
| 3000 | 296 | 0.5 |
| 3001 | 296.5 | - |
| 4000 | 131072 | 0.5 |
| 4001 | 131072.5 | - |
| 5000 | Inf | 无意义 |
| 5001 | Inf | - |
erf 函数,erf 函数是 C 标准库 <math.h> 中的函数,用于计算误差函数值)的非线性变化来确定的。#include <stdio.h>
#include <math.h>
#include <float.h>
#define TABLE_SIZE 65536 // 16位整数的范围是0到65535
// 定义一个函数来生成查找表
void generateLookupTable(double lower_bound, double upper_bound, double lookup_table[TABLE_SIZE]) {
double range = upper_bound - lower_bound;
for (int i = 0; i < TABLE_SIZE; i++) {
// 将0到65535的整数映射到指定的范围
double x = lower_bound + (double)i / TABLE_SIZE * range;
// 使用erf函数计算对应的值
lookup_table[i] = erf(x);
}
}
int main() {
double lower_bound = -5.0;
double upper_bound = 5.0;
double lookup_table[TABLE_SIZE];
generateLookupTable(lower_bound, upper_bound, lookup_table);
// 打印查找表的一部分示例
for (int i = 0; i < 10; i++) {
printf("Index: %d, Value: %lf\n", i, lookup_table[i]);
}
return 0;
}
generateLookupTable 函数接受下限 lower_bound 和上限 upper_bound 作为参数,以及一个用于存储查找表的数组 lookup_table。erf 函数值,存储在查找表中。main 函数中,我们定义了范围的下限和上限,调用 generateLookupTable 函数生成查找表,并打印查找表的前 10 个元素作为示例。erf 函数是 C 标准库中 <math.h> 头文件里用于计算误差函数的函数,其原型为:double erf(double x);
double 类型的浮点数作为参数,并返回一个 double 类型的结果。i 是整型,但在计算 x 时已经将其转换为 double 类型进行计算,然后将 x 传入 erf 函数,这是符合 erf 函数参数要求的。man 配置,在 Linux 系统中,你可以通过 man erf 命令来查看 erf 函数的详细手册页,其中会包含函数的功能描述、参数说明、返回值以及相关的示例等信息。如果你在 Windows 系统中使用的是 MinGW 等类似的开发环境,也可以通过相应的文档或在线资源来查看 erf 函数的详细信息。float 通常是32位,double 通常是64位。float 类型占用4个字节(32位),它能表示的有效数字一般为6 - 7位,取值范围约为±3.4×10−38到±3.4×1038。double 类型占用8个字节(64位),能表示的有效数字通常为15 - 16位,取值范围约为±1.7×10−308到±1.7×10308。erf 函数只有接受 double 类型参数的版本,没有接受 float 类型参数的版本。float 类型的变量,将其传递给 erf 函数时会自动进行类型转换,转换为 double 类型,所以不用担心类型不匹配的问题,程序可以正常运行并得到正确的结果。erff 函数,它是 erf 函数的单精度版本,接受 float 类型参数并返回 float 类型结果,但需要注意的是,erff 函数不是 C 标准库的一部分,在一些平台上可能需要链接额外的数学库才能使用。float 转换为双精度 double 通常不会丢失数据,一般也不会影响最终效果。float 转换为 double 时,数值本身会被准确地转换,只是在内存中以双精度的格式存储,额外的位会被填充为合适的值,通常不是简单地添加 0。由于 double 的精度更高、取值范围更大,它可以精确表示 float 能表示的所有值,所以在这种转换过程中不会有数据丢失或精度损失,能保证计算结果的准确性。float 值找到其对应的索引(即你说的之前用于生成查找表的那个整数)的 C 语言函数示例。代码基于之前生成查找表的程序进行扩展:#include <stdio.h>
#include <math.h>
#include <float.h>
#define TABLE_SIZE 65536 // 16位整数的范围是0到65535
// 定义一个函数来生成查找表
void generateLookupTable(double lower_bound, double upper_bound, double lookup_table[TABLE_SIZE]) {
double range = upper_bound - lower_bound;
for (int i = 0; i < TABLE_SIZE; i++) {
// 将0到65535的整数映射到指定的范围
double x = lower_bound + (double)i / TABLE_SIZE * range;
// 使用erf函数计算对应的值
lookup_table[i] = erf(x);
}
}
// 二分查找函数,返回给定值在查找表中最接近的索引
int binarySearch(double target, double lookup_table[TABLE_SIZE]) {
int left = 0;
int right = TABLE_SIZE - 1;
int result = -1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (lookup_table[mid] == target) {
return mid;
} else if (lookup_table[mid] < target) {
left = mid + 1;
result = mid;
} else {
right = mid - 1;
}
}
return result;
}
int main() {
double lower_bound = -5.0;
double upper_bound = 5.0;
double lookup_table[TABLE_SIZE];
generateLookupTable(lower_bound, upper_bound, lookup_table);
// 测试二分查找函数,给定一个float值查找对应的索引
float test_value = 0.3;
int index = binarySearch(test_value, lookup_table);
if (index != -1) {
printf("The index corresponding to the value %f in the lookup table is: %d\n", test_value, index);
} else {
printf("No exact match found, the closest index is: %d\n", index);
}
return 0;
}
generateLookupTable 函数用于生成之前的查找表,原理和之前一样。binarySearch 函数实现了二分查找算法。它接受一个目标值 target 和查找表 lookup_table 作为参数,在查找表中查找与目标值最接近的元素的索引。如果找到完全匹配的值,直接返回该索引;如果没有完全匹配的值,返回最接近的索引(这里选择比目标值小的最接近索引)。main 函数中,生成查找表后,给定一个测试值 test_value 调用 binarySearch 函数进行查找,并输出结果。binarySearch 函数,使其返回与给定目标值最接近的索引,而非仅仅返回第一个小于目标值的索引:#include <stdio.h>
#include <math.h>
#include <float.h>
#define TABLE_SIZE 65536 // 16位整数的范围是0到65535
// 定义一个函数来生成查找表
void generateLookupTable(double lower_bound, double upper_bound, double lookup_table[TABLE_SIZE]) {
double range = upper_bound - lower_bound;
for (int i = 0; i < TABLE_SIZE; i++) {
// 将0到65535的整数映射到指定的范围
double x = lower_bound + (double)i / TABLE_SIZE * range;
// 使用erf函数计算对应的值
lookup_table[i] = erf(x);
}
}
// 二分查找函数,返回给定值在查找表中最接近的索引
int binarySearch(double target, double lookup_table[TABLE_SIZE]) {
int left = 0;
int right = TABLE_SIZE - 1;
int closestIndex = -1;
double closestDiff = DBL_MAX;
while (left <= right) {
int mid = left + (right - left) / 2;
double diff = fabs(lookup_table[mid] - target);
if (diff < closestDiff) {
closestDiff = diff;
closestIndex = mid;
}
if (lookup_table[mid] == target) {
return mid;
} else if (lookup_table[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return closestIndex;
}
int main() {
double lower_bound = -5.0;
double upper_bound = 5.0;
double lookup_table[TABLE_SIZE];
generateLookupTable(lower_bound, upper_bound, lookup_table);
// 测试二分查找函数,给定一个float值查找对应的索引
float test_value = 0.3;
int index = binarySearch(test_value, lookup_table);
if (index != -1) {
printf("The index corresponding to the value %f in the lookup table is: %d\n", test_value, index);
} else {
printf("Failed to find an appropriate index.\n");
}
return 0;
}
binarySearch 函数中增加了 closestIndex 用于记录最接近目标值的索引,closestDiff 用于记录最接近的差值,初始值设为 DBL_MAX(表示最大的 double 类型值)。diff,如果这个差值小于当前记录的最小差值 closestDiff,则更新 closestDiff 和 closestIndex。closestIndex,这样就能找到与目标值最接近的表中元素的索引了。binarySearch 函数中添加了对目标值是否超出查找表对应范围的检查。如果目标值超出了生成查找表时设定的范围,就直接返回表示未找到的特殊值(这里使用 -1 表示)。#include <stdio.h>
#include <math.h>
#include <float.h>
#define TABLE_SIZE 65536 // 16位整数的范围是0到65535
// 定义一个函数来生成查找表
void generateLookupTable(double lower_bound, double upper_bound, double lookup_table[TABLE_SIZE]) {
double range = upper_bound - lower_bound;
for (int i = 0; i < TABLE_SIZE; i++) {
// 将0到65535的整数映射到指定的范围
double x = lower_bound + (double)i / TABLE_SIZE * range;
// 使用erf函数计算对应的值
lookup_table[i] = erf(x);
}
}
// 二分查找函数,返回给定值在查找表中最接近的索引,同时检查范围
int binarySearch(double target, double lower_bound, double upper_bound, double lookup_table[TABLE_SIZE]) {
// 检查目标值是否超出范围
if (target < erf(lower_bound) || target > erf(upper_bound)) {
return -1;
}
int left = 0;
int right = TABLE_SIZE - 1;
int closestIndex = -1;
double closestDiff = DBL_MAX;
while (left <= right) {
int mid = left + (right - left) / 2;
double diff = fabs(lookup_table[mid] - target);
if (diff < closestDiff) {
closestDiff = diff;
closestIndex = mid;
}
if (lookup_table[mid] == target) {
return mid;
} else if (lookup_table[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return closestIndex;
}
int main() {
double lower_bound = -5.0;
double upper_bound = 5.0;
double lookup_table[TABLE_SIZE];
generateLookupTable(lower_bound, upper_bound, lookup_table);
// 测试二分查找函数,给定一个float值查找对应的索引
float test_value = 0.3;
int index = binarySearch(test_value, lower_bound, upper_bound, lookup_table);
if (index != -1) {
printf("The index corresponding to the value %f in the lookup table is: %d\n", test_value, index);
} else {
printf("The value is out of the defined range or no appropriate index found.\n");
}
return 0;
}
binarySearch 函数增加了两个参数 lower_bound 和 upper_bound,用于传入生成查找表时的上下界范围。if 语句检查 target 是否小于 erf(lower_bound) 或者大于 erf(upper_bound),如果是,则直接返回 -1,表示目标值超出范围,无需进行二分查找。main 函数中调用 binarySearch 函数时,传入了相应的上下界范围参数,以便进行范围检查。#include <stdio.h>
#include <math.h>
#include <float.h>
#define TABLE_SIZE 65536 // 16位整数的范围是0到65535
// 生成基于CFT的查找表
void generateCFTLookupTable(double lower_bound, double upper_bound, double lookup_table[TABLE_SIZE]) {
double range = upper_bound - lower_bound;
for (int i = 0; i < TABLE_SIZE; i++) {
double x = lower_bound + (double)i / TABLE_SIZE * range;
lookup_table[i] = erf(x);
}
}
// 生成线性量化的查找表(这里只是逻辑,实际不需要表,直接计算)
double linearQuantization(double lower_bound, double upper_bound, int index) {
double range = upper_bound - lower_bound;
return lower_bound + (double)index / TABLE_SIZE * range;
}
int main() {
double lower_bound = -3.0;
double upper_bound = 5.0;
double cft_lookup_table[TABLE_SIZE];
generateCFTLookupTable(lower_bound, upper_bound, cft_lookup_table);
// 输出相邻索引的差值对比
printf("Index\tLinear Diff\tCFT Diff\n");
for (int i = 1000; i <= 3001; i += 1000) {
double linear_val1 = linearQuantization(lower_bound, upper_bound, i);
double linear_val2 = linearQuantization(lower_bound, upper_bound, i + 1);
double cft_val1 = cft_lookup_table[i];
double cft_val2 = cft_lookup_table[i + 1];
double linear_diff = linear_val2 - linear_val1;
double cft_diff = cft_val2 - cft_val1;
printf("%d\t%f\t%f\n", i, linear_diff, cft_diff);
}
return 0;
}
generateCFTLookupTable 函数用于生成基于 CFT 的查找表,与之前的实现类似。linearQuantization 函数根据给定的上下界和索引,计算线性量化的结果。main 函数中,首先生成基于 CFT 的查找表,然后通过循环,对于指定的索引(1000, 2000, 3000),分别计算线性量化和基于 CFT 的非线性量化的相邻索引间的差值,并输出对比结果。CFT Diff 都是 0.000000 是不正确的,这很可能是由于浮点数精度的问题导致差值被舍入为零了。在计算 CFT 差值时,由于 erf 函数在某些区域的变化可能相对平缓,两个相邻值的差值非常小,在输出时可能被舍入为零。long double)来减少这种舍入误差,或者调整输出格式,显示更多的小数位来观察到这些微小的差值。以下是修改后的代码,使用 long double 来提高精度,并修改输出格式以显示更多小数位:#include <stdio.h>
#include <math.h>
#include <float.h>
#define TABLE_SIZE 65536 // 16位整数的范围是0到65535
// 生成基于CFT的查找表
void generateCFTLookupTable(long double lower_bound, long double upper_bound, long double lookup_table[TABLE_SIZE]) {
long double range = upper_bound - lower_bound;
for (int i = 0; i < TABLE_SIZE; i++) {
long double x = lower_bound + (long double)i / TABLE_SIZE * range;
lookup_table[i] = erf(x);
}
}
// 生成线性量化的查找表(这里只是逻辑,实际不需要表,直接计算)
long double linearQuantization(long double lower_bound, long double upper_bound, int index) {
long double range = upper_bound - lower_bound;
return lower_bound + (long double)index / TABLE_SIZE * range;
}
int main() {
long double lower_bound = -3.0;
long double upper_bound = 5.0;
long double cft_lookup_table[TABLE_SIZE];
generateCFTLookupTable(lower_bound, upper_bound, cft_lookup_table);
// 输出相邻索引的差值对比
printf("Index\tLinear Diff\tCFT Diff\n");
for (int i = 1000; i <= 3001; i += 1000) {
long double linear_val1 = linearQuantization(lower_bound, upper_bound, i);
long double linear_val2 = linearQuantization(lower_bound, upper_bound, i + 1);
long double cft_val1 = cft_lookup_table[i];
long double cft_val2 = cft_lookup_table[i + 1];
long double linear_diff = linear_val2 - linear_val1;
long double cft_diff = cft_val2 - cft_val1;
printf("%d\t%.10Lf\t%.10Lf\n", i, linear_diff, cft_diff);
}
return 0;
}
lower_bound、upper_bound、lookup_table 以及函数的返回值等都改为 long double 类型,以提高计算精度。printf 的格式字符串,使用 %.10Lf 来显示 long double 类型的数值,并显示 10 位小数,这样可以更清楚地看到微小的差值。CFT 差值。