BCD 编码数字(卡西欧串行接口)
Encoding numbers in BCD (Casio serial interface)
我正在尝试创建一个设备,该设备通过带有 Arduino 的串行端口与 Casio fx-9750 计算器通信。我已经弄清楚如何接收值和解码 BCD,但我仍然坚持如何从浮点数创建所需的值(以传回)。
计算器发送一个数据包,有一个指数值,几个数据值,一个字节包含负数,虚部等信息,每个数据值都是前一个数据值的百分之一,所以首先是 10s 的数量,接下来是 0.1s 的数量,接下来是 0.001s 的数量,等等。这一直持续到 0.0000000000001s,尽管这超出了我真正需要的范围,所以准确度对我来说并不重要。我的接收程序的输出如下所示:
Exponent: 1
10s: 1
0.1s: 23
0.001s: 40
这代表 12.34。
我计算出的一般方程式是:(设 a=10s,b=0.1s,e=指数等)
((a*10)+(b*0.1)+(c*0.001))*10^(E-1)
如果指数改为二:
Exponent: 2
10s: 1
0.1s: 23
0.001s: 40
这将代表 123.4
这种每次丢百分之一的方法估计是因为他们用BCD可以每个字节存储两位数,所以让每一行有两位数是最有效的,因为每一行存储为一个字节。
我想出了一个方程式,可以通过计算小数点前的位数并减去二来计算指数,但是这看起来很乱,因为它涉及字符串。如果可能的话,我认为纯数学解决方案会更优雅。
从正常数字(例如 123.4)到这种排列的最快最简单的方法是什么?
使用 Arduino 语言的解决方案将不胜感激,但任何对所需数学过程的洞察力都将受到同等重视。
关于花车的编辑:
我应该澄清 - 我将在程序的其他部分处理浮点数,并希望我输入的值与任何大小的数字兼容(如前所述,在合理范围内)。我可以将它们相乘为整数或将它们转换为其他数据类型。
哈,真有趣!
#include <stdio.h>
#include <assert.h>
#include <math.h>
#include <float.h>
struct num_s {
// exponent
int e;
// v[0] is *10
// v[1] is *0.01
// v[2] is *0.0001
// and so on...
// to increase precision increase array count
int v[6];
};
#define NUM_VALSCNT (sizeof(((struct num_s*)0)->v)/sizeof(((struct num_s*)0)->v[0]))
// creates num_s object from a double
struct num_s num_create(double v) {
struct num_s t;
// find exponent so that v <= 10
t.e = 0;
while (fabs(v) >= 10.0) {
++t.e;
v /= 10.0;
}
// for each output number get the integral part of number
// then multiply the rest by 100 and continue
for (size_t i = 0; i < sizeof(t.v) / sizeof(t.v[0]); ++i) {
const double tmp = fmod(v, 1.0);
t.v[i] = v - tmp;
v = tmp * 100;
}
return t;
}
// converts back from num object to double
double num_get(struct num_s t) {
double denom = 10;
double ret = 0;
for (size_t i = 0; i < sizeof(t.v) / sizeof(t.v[0]); ++i) {
ret += denom * t.v[i];
denom /= 100;
}
return ret * pow(10, t.e - 1);
}
void num_println(struct num_s t) {
printf("%f =", num_get(t));
for (size_t i = 0; i < sizeof(t.v) / sizeof(t.v[0]); ++i) {
printf(" %d", t.v[i]);
}
printf(" %d\n", t.e);
}
// returns the precision of numbers
// the smallest number we can represent in num object
double num_precision(void) {
return pow(0.1, (NUM_VALSCNT - 1) * 2) * 10;
}
int num_unittests(void) {
const double tests[][3] = {
{ 123.49, 123.5, 123.51, }
};
for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i) {
const double tmp = num_get(num_create(tests[i][1]));
if (!(tests[i][0] <= tmp && tmp <= tests[i][2])) {
return i + 1;
}
}
return 0;
}
int main() {
num_println(num_create(12.3456789));
num_println(num_create(123.5));
num_println(num_create(12.35));
printf("%d\n", num_unittests());
return 0;
}
我正在尝试创建一个设备,该设备通过带有 Arduino 的串行端口与 Casio fx-9750 计算器通信。我已经弄清楚如何接收值和解码 BCD,但我仍然坚持如何从浮点数创建所需的值(以传回)。
计算器发送一个数据包,有一个指数值,几个数据值,一个字节包含负数,虚部等信息,每个数据值都是前一个数据值的百分之一,所以首先是 10s 的数量,接下来是 0.1s 的数量,接下来是 0.001s 的数量,等等。这一直持续到 0.0000000000001s,尽管这超出了我真正需要的范围,所以准确度对我来说并不重要。我的接收程序的输出如下所示:
Exponent: 1
10s: 1
0.1s: 23
0.001s: 40
这代表 12.34。
我计算出的一般方程式是:(设 a=10s,b=0.1s,e=指数等)
((a*10)+(b*0.1)+(c*0.001))*10^(E-1)
如果指数改为二:
Exponent: 2
10s: 1
0.1s: 23
0.001s: 40
这将代表 123.4
这种每次丢百分之一的方法估计是因为他们用BCD可以每个字节存储两位数,所以让每一行有两位数是最有效的,因为每一行存储为一个字节。
我想出了一个方程式,可以通过计算小数点前的位数并减去二来计算指数,但是这看起来很乱,因为它涉及字符串。如果可能的话,我认为纯数学解决方案会更优雅。
从正常数字(例如 123.4)到这种排列的最快最简单的方法是什么? 使用 Arduino 语言的解决方案将不胜感激,但任何对所需数学过程的洞察力都将受到同等重视。
关于花车的编辑: 我应该澄清 - 我将在程序的其他部分处理浮点数,并希望我输入的值与任何大小的数字兼容(如前所述,在合理范围内)。我可以将它们相乘为整数或将它们转换为其他数据类型。
哈,真有趣!
#include <stdio.h>
#include <assert.h>
#include <math.h>
#include <float.h>
struct num_s {
// exponent
int e;
// v[0] is *10
// v[1] is *0.01
// v[2] is *0.0001
// and so on...
// to increase precision increase array count
int v[6];
};
#define NUM_VALSCNT (sizeof(((struct num_s*)0)->v)/sizeof(((struct num_s*)0)->v[0]))
// creates num_s object from a double
struct num_s num_create(double v) {
struct num_s t;
// find exponent so that v <= 10
t.e = 0;
while (fabs(v) >= 10.0) {
++t.e;
v /= 10.0;
}
// for each output number get the integral part of number
// then multiply the rest by 100 and continue
for (size_t i = 0; i < sizeof(t.v) / sizeof(t.v[0]); ++i) {
const double tmp = fmod(v, 1.0);
t.v[i] = v - tmp;
v = tmp * 100;
}
return t;
}
// converts back from num object to double
double num_get(struct num_s t) {
double denom = 10;
double ret = 0;
for (size_t i = 0; i < sizeof(t.v) / sizeof(t.v[0]); ++i) {
ret += denom * t.v[i];
denom /= 100;
}
return ret * pow(10, t.e - 1);
}
void num_println(struct num_s t) {
printf("%f =", num_get(t));
for (size_t i = 0; i < sizeof(t.v) / sizeof(t.v[0]); ++i) {
printf(" %d", t.v[i]);
}
printf(" %d\n", t.e);
}
// returns the precision of numbers
// the smallest number we can represent in num object
double num_precision(void) {
return pow(0.1, (NUM_VALSCNT - 1) * 2) * 10;
}
int num_unittests(void) {
const double tests[][3] = {
{ 123.49, 123.5, 123.51, }
};
for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i) {
const double tmp = num_get(num_create(tests[i][1]));
if (!(tests[i][0] <= tmp && tmp <= tests[i][2])) {
return i + 1;
}
}
return 0;
}
int main() {
num_println(num_create(12.3456789));
num_println(num_create(123.5));
num_println(num_create(12.35));
printf("%d\n", num_unittests());
return 0;
}