Имя: Пароль:
1C
 
Обращение десятичной дроби в обыкновенную
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(числ/знам-ДрЧасть);
Если Дельта/ДрЧасть < Погрешность Тогда
прервать;
КонецЕсли;
Но в принципе это не нужно, так как при маленькой дельте на следующем шаге и числитель и знаменатель вырастут в очень много раз.
Глупец, лишенный способности посмеяться над собой вместе с другими, не сможет долго выносить программирование. Фредерик Брукс-младший