Кодирование чисел в BCD (последовательный интерфейс Casio)

Я пытаюсь создать устройство, которое подключается к калькулятору Casio fx-9750 через его последовательный порт с Arduino. Я выяснил, как получать значения и декодировать BCD, но я застрял на том, как создать требуемые значения из числа с плавающей запятой (для обратной передачи).

Калькулятор отправляет пакет данных с показателем степени, несколькими значениями данных и байтом, который содержит информацию об отрицательности, мнимых частях и т. Д. Каждое значение данных стоит одну сотую от предыдущего, поэтому первым является сумма 10 с, следующее значение 0,1 с, следующее значение 0,001 с и т. Д. Это продолжается до 0,0000000000001 с, хотя это выходит за пределы того, что мне действительно нужно, так что уровень точности не действительно важно для меня. Вывод моей принимающей программы выглядит следующим образом:

Exponent: 1
10s: 1
0.1s: 23
0.001s: 40

Это составляет 12,34.
Общее уравнение, которое я разработал, было: (пусть a = 10 с, b = 0,1 с, 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 будет высоко оценено, но любое понимание необходимого математического процесса будет одинаково ценно.

Изменить относительно поплавков:
Я должен уточнить — я буду иметь дело с плавающей точкой в ​​других частях моей программы и хотел бы, чтобы мои введенные значения были совместимы с числами любого размера (в разумных пределах, как указано выше). У меня нет проблем с умножением их на целые числа или приведением их к другим типам данных.

-2

Решение

Ха, это было весело!

#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;
}
0

Другие решения

Других решений пока нет …