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