|
Преобразовать число с плавающей точкой в простую дробь., Нужен оптимальный алгоритм пересчета |
|
|
|
Jun 8 2016, 12:56
|

Частый гость
 
Группа: Свой
Сообщений: 158
Регистрация: 15-10-07
Из: Й-Ола
Пользователь №: 31 376

|
Встала задача преобразовать число single/double в простую дробь. Классическое правило: 1.2345 = 12345 / 10000 Находим наибольший общий делитель НОД(12345,10000)=5 и сокращаем дробь: 12345 / 10000 = 2469 / 2000 Еще нашел способ: CODE d = 0.12345; // Исходная дробь, может быть любой a0 = 0; a1 = 1; b0 = 1; b1 = 0; while(не_достигнута_нужная точность) { N = Floor(d); a = N * a1 + a0; b = N * b1 + b0; printf("%d / %d = %f\n", a, b, a/b); a0 = a1; a1 = a; b0 = b1; b1 = b; d = 1/(d - N); }
Первый способ дает неоптимальные числа (слишком большие) при той-же точности, у второго в алгоритме есть дыры типа деления на ноль. Может кто-то уже проходил этот путь? Что посоветуете?
|
|
|
|
|
Jun 8 2016, 13:57
|

Частый гость
 
Группа: Свой
Сообщений: 158
Регистрация: 15-10-07
Из: Й-Ола
Пользователь №: 31 376

|
Цитата(_pv @ Jun 8 2016, 16:46)  для чего, если не секрет? Нужно вводить коэффициент редуктора двигателя в частотник из верхнего софта.
|
|
|
|
|
Jun 8 2016, 14:00
|

я только учусь...
     
Группа: Модераторы
Сообщений: 3 447
Регистрация: 29-01-07
Из: Украина
Пользователь №: 24 839

|
Цитата(M_Andrey @ Jun 8 2016, 16:57)  Нужно вводить коэффициент редуктора двигателя в частотник из верхнего софта. посмотритеMATLAB: Код rat(pi) ans = 3 + 1/(7 + 1/(16)) rat(pi, 1e-12) ans = 3 + 1/(7 + 1/(16 + 1/(-294 + 1/(3 + 1/(-4 + 1/(5)))))) [n,d]=rat(pi); [n d] ans = 355 113 [n, d]=rat(pi, 1e-12); [n d] ans = 5419351 1725033 s = rats(pi) s = 355/113 s = rats(pi, 26) s = 5419351/1725033
Причина редактирования: Избыточное цитирование
--------------------
If it doesn't work in simulation, it won't work on the board.
"Ты живешь в своих поступках, а не в теле. Ты — это твои действия, и нет другого тебя" Антуан де Сент-Экзюпери повесть "Маленький принц"
|
|
|
|
|
Jun 8 2016, 14:52
|
Гуру
     
Группа: Свой
Сообщений: 2 563
Регистрация: 8-04-05
Из: Nsk
Пользователь №: 3 954

|
Цитата(M_Andrey @ Jun 8 2016, 21:12)  эти коэффициенты наладчики будут вводить на объектах из верхнего софта (HMI SCADA), программа ПЛК получает число (double), пересчитывает в числитель и знаменатель, и передает их частотнику. ну раз наладчики вводят, то перебор всех 30000 значений для поиска оптимального могут и подождать лишнюю милисекунду. double n = 1.2345; double maxErr = 0.0001; int denom = 1; double err = n; for(int i = 1; i <= 30000; i++){ double e = abs((double)((int)(n * i + 0.5)) / i - n ); if (e < err){ err = e; denom = i;} if (e < maxErr) break; } получившаяся дробь: (n * denom + 0.5) / denom
|
|
|
|
|
Jun 8 2016, 16:19
|

Частый гость
 
Группа: Свой
Сообщений: 158
Регистрация: 15-10-07
Из: Й-Ола
Пользователь №: 31 376

|
Цитата(Tanya @ Jun 8 2016, 18:05)  Не пойму как непрерывную дробь применить в моем случае. PS. А вот "подходящая дробь" мой случай  Спасибо.
|
|
|
|
|
Jun 9 2016, 07:29
|

Частый гость
 
Группа: Свой
Сообщений: 158
Регистрация: 15-10-07
Из: Й-Ола
Пользователь №: 31 376

|
Цитата(M_Andrey @ Jun 8 2016, 19:19)  PS. А вот "подходящая дробь" мой случай  Спасибо. Оказалось что второй способ в моем первом посте и есть реализация "подходящей дроби". Вот только беда в том что постоянное деление (1/х) в каждой итеррации приводит к погрешности при вычислении даже конечной дроби.
|
|
|
|
|
Jun 9 2016, 09:04
|

Частый гость
 
Группа: Свой
Сообщений: 158
Регистрация: 15-10-07
Из: Й-Ола
Пользователь №: 31 376

|
Цитата(jcxz @ Jun 9 2016, 11:25)  Теперь разложите числитель и знаменатель на простые сомножители и сократите общую часть их. Получите числитель и знаменатель в виде: 2^K1 * 3^K2 * 5^K3 * 7^K4... (где ^ - возведение в степень). Выберите минимальную степень из каждой пары Kn и поделите на неё. А как их искать - перебором? Мне нужен машинный алгоритм.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|