![]() |
![]() |
![]() |
|
Обращение десятичной дроби в обыкновенную | ☑ | ||
---|---|---|---|---|
0
Lyolik
03.02.06
✎
10:08
|
Как это сделать на языке 1С.
|
|||
1
acsent
03.02.06
✎
10:09
|
0.1234 = 1234/10000
|
|||
2
Lyolik
03.02.06
✎
10:31
|
нужно этк дробь сократить и привести к виду 10/81.
|
|||
3
Lyolik
03.02.06
✎
10:51
|
может кто подскажет как дробь сократить?
|
|||
4
Бешенная Нога
03.02.06
✎
10:53
|
ели дробь вида
1/151 ты ее никогда не приведешь к виду х/81, чтобы х - было целое число |
|||
5
Широкий
03.02.06
✎
10:55
|
в цикле по значениям от 0 до 9 перебирай - смотришь имеет ли числитель и знаменатель общие делители - есть сокращает - снова цикл ... и т.д приведешь дробь 1234/1000 к другому виду
|
|||
6
airyashov
03.02.06
✎
10:56
|
НОД и НОК ищи алгоритм стандартный
|
|||
7
Mort
03.02.06
✎
11:02
|
Десятичная дробь значит что в знаменатель всегда кратен только простым 2 и 5. Пока числитель делится на 2 или 5 дели. Когда не будет делится считай нашёл.
|
|||
8
Широкий
03.02.06
✎
11:04
|
(7)3/9
|
|||
9
Simod
03.02.06
✎
11:05
|
+(6) или алгоритм Эвклида.
|
|||
10
Mort
03.02.06
✎
11:05
|
Ага. Преобразуй 3/9 в десятичную дробью.
|
|||
11
sb_sash
03.02.06
✎
11:07
|
(5) какой в цикле от 0 до 9?! в цикле от 1 до ЦелаяЧасть(числитель/2)
|
|||
12
NS
03.02.06
✎
11:07
|
Если сократить дробь, то а/б =
(а / НОД(а,б)) / (в / НОД(а,б)) Функция НОД(а,б) Если б=0 Тогда возврат а; Иначе возврат НОД(б,а%б); КонецЕсли; КонецФункции // Но есть еще способы приближенного сокращения дроби с данной точностью. |
|||
13
Simod
03.02.06
✎
11:08
|
Порылся у себя. Алгоритм Эвклида:
//****************************************************************************** // Поиск() // // Параметры: // Нет // // Возвращаемое значение: // Нет // // Описание: // Поиск наибольшего делителя для двух целых положительных чисел // Процедура Поиск() М = р_Значение1; Н = р_Значение2; Пока 1 = 1 Цикл Р = М%Н; Если Р = 0 Тогда Р = Н; Прервать; Иначе М = Н; Н = Р; КонецЕсли; КонецЦикла; Сообщить(Р); КонецПроцедуры // Поиск() |
|||
14
NS
03.02.06
✎
11:08
|
Чтоб изначально привести число к виду а/б
а=начЧисло; б=1; Пока цел(а)<>а цикл а=а*10; б=б*10; КонецЦикла; |
|||
15
evGenius
03.02.06
✎
11:10
|
(7) дело сказал!
У знаменателя делители только 2 и 5. Зачем перебирать все? |
|||
16
Широкий
03.02.06
✎
11:11
|
(7) Признаю... проще смотреть делители 2 и 5
|
|||
17
NS
03.02.06
✎
11:11
|
(15) Их вообще перебирать не надо.
см. (12) |
|||
18
Mort
03.02.06
✎
11:11
|
Вот итог:
Числитель = смотри(14) Знаменатель = смотри.(14) Пока цел(Числитель/2)=Числитель/2 Цикл Числитель=Числитель/2 Знаменатель=Знаменатель/2 КонецЦикла Пока цел(Числитель/5)=Числитель/5 Цикл Числитель=Числитель/5 Знаменатель=Знаменатель/5 КонецЦикла |
|||
19
Mort
03.02.06
✎
11:13
|
Не увидел (12) тож катит
|
|||
20
evGenius
03.02.06
✎
11:14
|
(17) Дольше.
|
|||
21
evGenius
03.02.06
✎
11:15
|
(20)+ Да еще и рекурсия...
|
|||
22
NS
03.02.06
✎
11:17
|
(20) Проверял?
Рекурсия леко убирается... Пока б>0 цикл с=б; б=а%б; а=с; КонецЦикла; |
|||
23
NS
03.02.06
✎
11:18
|
(+22) По завершении цикла в "а" будет результат.
|
|||
24
NS
03.02.06
✎
11:26
|
Кстати, в (18) - Ошибка, неверный алгоритм.
Попробуй 8/10 |
|||
25
NS
03.02.06
✎
11:28
|
Процедура Сформировать()
Нач=0.4096; Числитель=нач; Знаменатель=1; Пока цел(числитель)<>Числитель Цикл Числитель=Числитель*10; Знаменатель=Знаменатель*10; КонецЦикла; к=_GetPerformanceCounter(); Для м=1 по 10000 цикл а=числитель; б=Знаменатель; Пока б>0 цикл с=б; б=а%б; а=с; КонецЦикла; КонецЦикла; сообщить(""+((_GetPerformanceCounter()-к)/10000)+" мс."); сообщить(""+(Числитель/а)+"/"+(Знаменатель/а)); КонецПроцедуры |
|||
26
lisss
03.02.06
✎
11:30
|
Функция ОбыкновевеннаяДробь(Чис=0)
Числ = Чис; Стр = Строка(Числ); Стр = Число(СтрЗаменить(Стр,".","")); Числ = Стр/Чис; Пока (Числ%2=0) и (Стр%2=0) Цикл Числ = Числ/2; Стр = Стр/2; КонецЦикла; Пока (Числ%5=0) и (Стр%5=0) Цикл Числ = Числ/5; Стр = Стр/5; КонецЦикла; Возврат(?(Числ=1,""+Стр,""+Стр+"/"+Числ)); КонецФункции |
|||
27
lisss
03.02.06
✎
11:33
|
+(26)Так вернее..... :)
Функция ОбыкновевеннаяДробь(Чис=0) Если Чис<>0 Тогда Числ = Чис; Стр = Строка(Числ); Стр = Число(СтрЗаменить(Стр,".","")); Числ = Стр/Чис; Пока (Числ%2=0) и (Стр%2=0) Цикл Числ = Числ/2; Стр = Стр/2; КонецЦикла; Пока (Числ%5=0) и (Стр%5=0) Цикл Числ = Числ/5; Стр = Стр/5; КонецЦикла; Возврат(?(Числ=1,""+Стр,""+Стр+"/"+Числ)); Иначе Возврат("0"); КонецЕсли; КонецФункции |
|||
28
Lyolik
03.02.06
✎
12:01
|
Большое спасибо за мысли. Хочу уточнить условие. Есть дробь 1/6 преобразуем в десятичную = 0,1666666666666... ее опять нужно преобразовать в 1/6 а не в 833/5000.
|
|||
29
NS
03.02.06
✎
12:02
|
(28) Это уже алгоритмы приближенного преобразования...
Сейчас попробую вспомнить - что-то сомения у меня возникают, что в инете это есть... |
|||
30
NS
03.02.06
✎
12:07
|
Вспомнил...
|
|||
31
Lyolik
03.02.06
✎
12:17
|
(30) и ...
|
|||
32
NS
03.02.06
✎
12:19
|
Представляем в виде дроби -
1/(Х1+1/(Х2+1/(Х3+...)) Сейчас забацаю. |
|||
33
miki
03.02.06
✎
12:22
|
Вот еще был вариант, через приближения.
Код не претендует на оптимальность. ПисАлось по просьбе чела "очень срочно" за время в одну банку пива. Сначала были мысли доработать, но всё некогда. Находит ближайшую дробь с двухзначным знаменателем (кому надо больше - замените 99 на 99скольконадораз, можно переделать, чтобы max кол-во разрядов знаменателя передавать как параметр). //*********************************** Function ПреобразоватьВДробь(ДесЧисло) ЦелЧасть=Int(ДесЧисло); ДесЧасть=ДесЧисло-ЦелЧасть; If ДесЧасть=0 Then Return (Format(ЦелЧасть,"Ч0")); EndIf; Вариант=0;Eps=100; ОК=0; For _Знам=2 To 99 Do For _Числ=1 To (_Знам-1) Do Вариант=_Числ/_Знам; If Вариант=ДесЧасть Then ОК=1; Числ=_Числ;Знам=_Знам; Break; EndIf; If Вариант>ДесЧасть Then Eps1=(Вариант-ДесЧасть)/ДесЧасть Else Eps1=(ДесЧасть-Вариант)/ДесЧасть EndIf; If Eps1<Eps Then Числ=_Числ; Знам=_Знам; Eps=Eps1; EndIf; EndDo; If ОК=1 Then Break; EndIf; EndDo; Return(Format(ЦелЧасть,"Ч0")+" "+Числ+"/"+Знам); EndFunction //********************** |
|||
34
lisss
03.02.06
✎
12:26
|
(33)отрицательные числа работают неправильно.... впрочем как и в (25)....
|
|||
35
miki
03.02.06
✎
12:28
|
(34)Млять..., ну дык возьми модуль, потом минус дорисуй...
|
|||
36
lisss
03.02.06
✎
12:30
|
(35)я проще сделал :) см 27....
|
|||
37
lisss
03.02.06
✎
12:31
|
+(36) и работает быстрее....
|
|||
38
miki
03.02.06
✎
12:44
|
(36)Возвращает только неправильные дроби, т. е. не выделяет целую часть.
Чётных знаменателей не будет. => точность может быть ниже, чем в (33). (37) Согласен полностью. |
|||
39
Lyolik
03.02.06
✎
12:44
|
Метод (33) вроде нормально делает то что надо.
|
|||
40
NS
03.02.06
✎
12:45
|
Процедура Приближение(ДрЧасть,а,числ,Знам)
Если ДрЧасть=0 Тогда Числ=0; Знам=1; Иначеесли а=1 тогда Числ=1; Знам=Окр(1/ДрЧасть,0); Иначе ЗН=1/ДрЧасть; ЗН1=Окр(ЗН,0); Др=ЗН-ЗН1; Ч=0; З=0; Приближение(Др,а-1,Ч,З); числ=З; Знам=ЗН1*З+Ч; КонецЕсли; Если Знам<0 Тогда Числ=-Числ; Знам=-Знам; КонецЕсли; КонецПроцедуры Процедура Сформировать() нач=3.14159265; ДрЧасть=нач-цел(нач); Сообщить(ДрЧасть); Для а=1 по 10 цикл Числ=0; Знам=0; Приближение(ДрЧасть,а,числ,Знам); Сообщить(""+Числ+"/"+Знам+"="+окр(числ/знам,10)); Если Числ/Знам=ДрЧасть Тогда прервать; КонецЕсли; КонецЦикла; КонецПроцедуры |
|||
41
miki
03.02.06
✎
12:45
|
(38)+ т.е. "НЕЧётных знаменателей не будет", сорри.
|
|||
42
NS
03.02.06
✎
12:51
|
Процедура Приближение(ДрЧасть,а,числ,Знам)
Если ДрЧасть=0 Тогда Числ=0; Знам=1; Иначеесли а=1 тогда Числ=1; Знам=Окр(1/ДрЧасть,0); Иначе ЗН=1/ДрЧасть; ЗН1=Окр(ЗН,0); Др=ЗН-ЗН1; Ч=0; З=0; Приближение(Др,а-1,Ч,З); числ=З; Знам=ЗН1*З+Ч; КонецЕсли; Если Знам<0 Тогда Числ=-Числ; Знам=-Знам; КонецЕсли; КонецПроцедуры Процедура Сформировать() нач=0.33333; ДрЧасть=нач-цел(нач); Сообщить(ДрЧасть); Для а=1 по 10 цикл Числ=0; Знам=0; Приближение(ДрЧасть,а,числ,Знам); Если числ>100 Тогда прервать; КонецЕсли; Сообщить(""+Числ+"/"+Знам+"="+окр(числ/знам,10)); Если Числ/Знам=ДрЧасть Тогда прервать; КонецЕсли; КонецЦикла; КонецПроцедур //Вот так с ограничением на размер числителя... |
|||
43
miki
03.02.06
✎
12:52
|
(40) Теряешь целую часть.
Для числа нач=3.14159265; Вариант (27) возвращает 314159/100000 Вариант (33) возвращает 3 16/113 Вариант (40) возвращает: . 1/7=0.1428571429 . 16/113=0.1415929204 . 431/3044=0.1415900131 . 3432/24239=0.1415899996 . 14159/100000=0.14159 |
|||
44
NS
03.02.06
✎
12:53
|
(43) Ничего я не теряю. Я показываю как преобразовать дробную часть.
Напиши Сообщить(""+цел(нач)+" "+... а тут что было написано...); |
|||
45
NS
03.02.06
✎
12:55
|
Процедура Приближение(ДрЧасть,а,числ,Знам)
Если ДрЧасть=0 Тогда Числ=0; Знам=1; Иначеесли а=1 тогда Числ=1; Знам=Окр(1/ДрЧасть,0); Иначе ЗН=1/ДрЧасть; ЗН1=Окр(ЗН,0); Др=ЗН-ЗН1; Ч=0; З=0; Приближение(Др,а-1,Ч,З); числ=З; Знам=ЗН1*З+Ч; КонецЕсли; Если Знам<0 Тогда Числ=-Числ; Знам=-Знам; КонецЕсли; КонецПроцедуры Процедура Сформировать() нач=0.1234 ; ДрЧасть=нач-цел(нач); Сообщить(ДрЧасть); Для а=1 по 10 цикл Числ=0; Знам=0; Приближение(ДрЧасть,а,числ,Знам); Если числ>100 Тогда прервать; КонецЕсли; Сообщить(""+Цел(Нач)+" "+Числ+"/"+Знам+"="+окр(числ/знам,10)); Если Числ/Знам=ДрЧасть Тогда прервать; КонецЕсли; КонецЦикла; КонецПроцедуры // Возвращает в (1), как раз как просил (2). |
|||
46
lisss
03.02.06
✎
12:59
|
(38)целую часть выделять не просили....
"Чётных знаменателей не будет. => точность может быть ниже, чем в (33)." ЭТО ТЫ ОТКУДА ВЗЯЛ???? |
|||
47
NS
03.02.06
✎
13:01
|
(46) Расслаютесь. В (45) "Правильный" алгоритм, которому уже несоклько веков.
Читал в библиотечке "Квант" (вроде, хотя еще брошурки таки тонкие были, не помню как назывались, может в них) ЗЫ. Во у меня пямять! ;-)) |
|||
48
NS
03.02.06
✎
13:02
|
(+47) Читал, когда еще в школе учился... Лет 20!!! Назад.
|
|||
49
lisss
03.02.06
✎
13:03
|
(47)вы уже решаете как сократить любую дробь.... вначале было десятичную....
|
|||
50
Бешенная Нога
03.02.06
✎
13:04
|
50/50
|
|||
51
NS
03.02.06
✎
13:06
|
(49) Вначале - смотри (1,2) Видишь 10/81?
Это не сокращение десятичной дроби, а представление иррационального числа в виде десятичной дроби (приближения) - в общем случае. |
|||
52
conv
03.02.06
✎
13:12
|
Взяли на двоих пол-литры . Скока раз разольём её по 100 грамм ?
|
|||
53
NS
03.02.06
✎
13:42
|
Процедура Приближение(ДрЧасть,а,числ,Знам)
Если ДрЧасть=0 Тогда Числ=0; Знам=1; Иначеесли а=1 тогда Числ=1; Знам=Окр(1/ДрЧасть,0); Иначе ЗН=1/ДрЧасть; ЗН1=Окр(ЗН,0); Др=ЗН-ЗН1; Ч=0; З=0; Приближение(Др,а-1,Ч,З); числ=З; Знам=ЗН1*З+Ч; КонецЕсли; Если Знам<0 Тогда Числ=-Числ; Знам=-Знам; КонецЕсли; КонецПроцедуры Процедура Сформировать() нач=3.1234 ; ДрЧасть=нач-цел(нач); Сообщить(Нач); Для а=1 по 10 цикл Числ=0; Знам=0; Приближение(ДрЧасть,а,числ,Знам); Если числ>1000 Тогда прервать; КонецЕсли; Сообщить(""+Цел(Нач)+" "+Числ+"/"+Знам+"="+окр(Цел(нач)+числ/знам,10)); Если Числ/Знам=ДрЧасть Тогда прервать; КонецЕсли; КонецЦикла; КонецПроцедуры //Вот так совсем корректно. |
|||
54
Lyolik
03.02.06
✎
13:55
|
NS большое спасибо, проверяю на базе клиента. А ограничение 100 или 1000 выставлю в константе. Практика покажет как лучше.
|
|||
55
NS
03.02.06
✎
13:58
|
(54) Еще на дельту - относительное отклонение можно ограничение ставить.
|
|||
56
Lyolik
03.02.06
✎
14:13
|
(55)непонял :(
|
|||
57
NS
03.02.06
✎
14:19
|
Дельта=ABS(числ/знам-ДрЧасть);
Если Дельта/ДрЧасть < Погрешность Тогда прервать; КонецЕсли; Но в принципе это не нужно, так как при маленькой дельте на следующем шаге и числитель и знаменатель вырастут в очень много раз. |
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |