Форум » [x]Harbour » xHarbour и возможно Harbour неправильно складывает! Как победить? » Ответить

xHarbour и возможно Harbour неправильно складывает! Как победить?

AndreyZh: В задачах по ЕГАИС нужно переводить 36 ричное число в десятиричное и отображать в виде строки дополненное нулями. Есть конкретные значения 22N00001CJFID3CDJKV3SXP412170130000055IEUMY72S745DV7196PEFENFADYFS4F - код акцизной марки 1CJFID3CDJKV - преобразуем данный блок 0177469000003644511 - ПРАВИЛЬНОЕ число по "1С" или Web трансляторам 0177469000003644661 - считает xHarbour по "ручным" алгоритмам или через встроенные функции 0177469000003644662 - считает xHarbour, если nSum задать, как комментарии Код моих "мучений": [pre2] nLen := Len( cA ) cB := cA nSum := 0 // 0.0000 FOR nX := 1 TO nLen nM := 1 FOR nY := 1 TO nLen - nX DO nM := nM*36 nSum := nSum + nM * ( At( Subs(cA,nX,1), "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" ) - 1 ) NEXT nX cA := Ntoc( nSum, 10, 19, "0" ) WAIT cA+" "+Ntoc( Cton(cB,36), 10, 19, "0" ) [/pre2] Подскажите пожалуйста, хоть вставкой на С - уже мозги кипят

Ответов - 15

Haz: AndreyZh пишет: 1CJFID3CDJKV - преобразуем данный блок 0177469000003644511 - ПРАВИЛЬНОЕ число по "1С" или Web трансляторам CTON( '1CJFID3CDJKV', 36 ) = 177469000003644511

Dima: Haz пишет: CTON( '1CJFID3CDJKV', 36 ) = 177469000003644511 Результат в PADL и добиваем нулями.

Haz: Dima пишет: Результат в PADL и добиваем нулями. PADL(CTON( '1CJFID3CDJKV', 36 ), 19, '0')


AndreyZh: Делаю "то же" самое: Ntoc( Cton(cB,36), 10, 19, "0" ) ... что глючит Ntoc или комп - сейчас проверю ваши рекомендации

Dima: AndreyZh пишет: Делаю "то же" самое: Ntoc( Cton(cB,36), 10, 19, "0" ) нет не тоже Haz пишет: PADL(CTON( '1CJFID3CDJKV', 36 ), 19, '0') Вот так можно (не проверял) PADL(Ntoc( Cton(cB,36) ), 19, "0" )

Dima: AndreyZh пишет: Ntoc( Cton(cB,36), 10, 19, "0" ) Проверил именно такой код результат 0177469000003644511 ЗЫ Harbour

AndreyZh: Всем огромное СПАСИБО!!! Успокоили, что xHarbour считает ПРАВИЛЬНО, как при использовании Cton, так и при алгоритме преобразования, но НЕПРАВИЛЬНО тогда работают функции: ПРАВИЛЬНО Padl( nSum, 19, "0" ) или Padl( Cton(cB,36), 19, "0" ) НЕПРАВИЛЬНО Padl( Ntoc(nSum), 19, "0" ) или Padl( Alltrim(Str(nSum,19)), 19, "0" ) или Ntoc( nSum, 10, 19, "0" ) или Ntoc( Cton(cB,36), 10, 19, "0" ) то есть "глючат" Ntoc, Str?

Pasha: [x]harbour поддерживает тип LONGLONG (64 битные целые), точности которого достаточно для представления 12-значного целого с базой 36. Если nSum задать как 0.0, будет использоваться тип double, точности которого уже недостаточно, вот и результат будет с погрешностью. Код ваших мучений считает nSum правильно, поскольку задействуется только тип LONGLONG. Дальнейшее использование cton/ntoc излишне. Чтобы перевести nSum в строку, достаточно вызвать Str(nSum, 19), ну и заменить ведущие пробелы на нули.

AndreyZh: Dima пишет: Dima пишет: Проверил именно такой код результат 0177469000003644511 Такой был изначально и не работал... да и сейчас перепроверял Windows 7/64 Как бы то ни было ВЫ МНЕ ВСЕ ОЧЕНЬ СИЛЬНО ПОМОГЛИ!!!

AndreyZh: А ВОТ И НИ ФИГА!!! Для одного преобразования "подобрали" правильно работающую функцию... и действительно ожидаемый результат, а для других значений уже не прокатывает Примеры правильных результатов: 1CJFID3CD 0177469000003644511 1CJFID3CE 0177469000003704221 54KNI68SC 0150367000002817036 Уже не получается...

Dima: AndreyZh пишет: 1CJFID3CD Да тут и строка покороче будет чем в первом посте , возможно дело не в этом

AndreyZh: Сегодня уже не в себе... Действительно не работает, но коды я беру с оборудования. Вероятно в сообщение неправильно скописпастил... С Вашего разрешения, завтра на свежую голову набросаю кучу примеров, где есть неверная перекодировака

Pasha: В xHarbour функции cton/ntoc реализованы в коде prg Например, там есть строка вроде nInt := INT( nNum / nBase) Рерультат nNum / nBase будет иметь тип double, а использование этого типа для таких больших чисел может приводить к погрешности. В Harbour эти функции сделаны на С, там погрешности быть не может.

Dima: AndreyZh В этой теме много пишут (я особо не вникал , так как не в теме) http://olegon.ru/showthread.php?t=23079&page=26

AndreyZh: Dima пишет: В этой теме много пишут (я особо не вникал , так как не в теме) http://olegon.ru/showthread.php?t=23079&page=26 Это обсуждение моей "мегасистемы" под ЕГАИС, в которой и возникла данная "заморочка", но с Ваше Dima, Pasha проникся сутью проблемы и кажется с Вашей помощью её полностью победил. Для других читателей: 1. Считает (x)Harbour правильно, но не всегда с требуемой точностью. Например задавая nSum:=0.0 вынуждал его работать с малой точностью Double, что приводило к округлениям на больших числах, а надо было (=0), что уже приводило к работе с длинными целыми; 2. Также использовании Cton/Ntoc использовались операции, приводящие к округлениям. На небольших числах этого не замечалось, но в моей заморочке давало неверный результат. Правильно работающий код сегодня проверенный на 10 акцизках и сличении с примерами транслятора: http://www.translatorscafe.com/cafe/units-converter/numbers/calculator/decimal-to-base-36/ [pre2] cCod := Upper( Alltrim(cCod) ) IF Len(cCod) <> 68 THEN Errmess("Длина кода акцизной марки точно равняется 68 знакам! У Вас не так = "+Str(Len(cCod),2),cError); RETU /* Номер не всегда начинается с 9 знака - более сложный алгоритм его выделения. Код АП правильно определяется в случае вхождения 00000 иначе никак не смог получить правильный код - какая-то лажа или с примерами марок (старые) или с алгоритмом 10.12.2015 Использую алгоритмы ручного преобразования из 36 ричного числа в 19 значное 10 ричное представление */ cTabWorker := cCod // Для передачи в отчет ШК акцизной марки // Выбираем разное число преобразуемых кодов IF Subs( cCod,4,5 ) == "00000" cA := Subs( cCod,9,11 ) ELSE cA := Subs( cCod,8,12 ) ENDI nLen := Len( cA ) cB := cA // Расчет в десятиричной систем (=0) делает переменную LongInteger, а если (=0.0) то Double, что уменьшает точность nSum := 0 FOR nX := 1 TO nLen nM := 1 FOR nY := 1 TO nLen - nX DO nM := nM*36 nSum := nSum + nM * ( At( Subs(cA,nX,1), "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" ) - 1 ) NEXT nX // Варианты использования Ntoc(nSum), Str(nSum,19) приводят к округлениям и потери точности cA := Padl( nSum, 19, "0" ) // Просто выравнием число пополняя нулями @ 0,0 SAY cA+" "+cTabWorker Inkey( 0 ) [/pre2]



полная версия страницы