LINUX.ORG.RU

[ненависть] C++

 


0

1

Господа, посоветуйте, как отучить компилятор понимать выражение

cln::cl_F x;

3/8*x
как
cln::cl_F x;

(3/8)*x = 0*x = 0
?

Переписывать код как

cln::cl_F x;

x*(3/8)
дюже неохота — его порядка 1000 строк

Вообще что это: выкрутасы компилятора или непродуманный синтаксис языка (shift/reduce conflict)? Класс, с которым такое происходит — cln::cl_F — взят из библиотеки cln (Class Library for Numbers)

Синтаксис Си, и C++ - говно, это понятно.
В данном случае все по стандарту - что первое из цепочки операций с одинаковым приоритетом - то и первым выполняется.
И тут спасут только живительные скобки.

А авторы библиотеки, что, на другом каком-то языке ее писали?

Love5an
()
Ответ на: комментарий от Love5an

В математике операция «/» на целых числах означает создание рациональной дроби, что для меня было бы perfectly OK, но никак не 'div'. Блин, не хочу переписывать кучу кода. Кого бы убить за это...

annoynimous ★★★★★
() автор топика

Проблема в том, что код автоматически сгенерирован, и генератору непросто объяснить, что в C/C++ свои правила вычисления выражений...

annoynimous ★★★★★
() автор топика
Ответ на: комментарий от annoynimous

>Проблема в том, что код автоматически сгенерирован, и генератору непросто объяснить, что в C/C++ свои правила вычисления выражений...

Значит, генератор кривой, и его надо переписать или выкинуть нахрен. Или заставить расставлять повсюду круглые скобки, чтобы было как у людей.

В математике операция «/» на целых числах означает создание рациональной дроби, что для меня было бы perfectly OK, но никак не 'div'.

В CL оно так и делается. Use Common Lisp, Luke!

Love5an
()

всё правильно компилятор сделал, / и * имеют одинаковый приоритет

Переписывать код как

cln::cl_F x;

x*(3/8)

не так, а вот так

3.0/8*x

этому на первом курсе учат :)

//да, понимаю что можно было забыть

shty ★★★★★
()
Ответ на: комментарий от annoynimous

Блин, не хочу переписывать кучу кода. Кого бы убить за это...

очевидно же, того кто этот код писал без тестирования

shty ★★★★★
()
Ответ на: комментарий от annoynimous

Проблема в том, что код автоматически сгенерирован, и генератору непросто объяснить, что в C/C++ свои правила вычисления выражений...

а что, хороший подход, давайте теперь под Ваш кривой генератор поменяем весь язык

shty ★★★★★
()
Ответ на: комментарий от annoynimous

Проблема в том, что код автоматически сгенерирован, и генератору непросто объяснить, что в C/C++ свои правила вычисления выражений...

Так проблема не в си++ :) Правьте генератор.

Надо было читать документацию, как пишешь генератор. Надо заменить лубое число value на As(type)(value)

http://www.ginac.de/CLN/cln_3.html#SEC11

ogronom
()

> Переписывать код как

x*(3/8)


ТС заслуживает всяких нехороших слов в больших количествах

aho
()
Ответ на: комментарий от aho

ТС заслуживает всяких нехороших слов в больших количествах

да не, просто порой «замануха» нападает, сидишь и понимаешь что проблема выеденного фигового листа не стоит, а мысль вертится и вертится как-то не конструктивно :)

shty ★★★★★
()

>Переписывать код как

дюже неохота - его порядка 1000 строк

sed -i s/'3/8*x'/'3.0/8*x'/g code.cpp

?

record ★★★★★
()

Ладно, тема закрыта, написал скрипт, где седом переделал все в формат 3*x/8. Но таки ненависть!

annoynimous ★★★★★
() автор топика
Ответ на: комментарий от catap

> 1.0*3/8*x сделают то что ты хочешь ;)

Так нельзя, потому что 1.0*3/8*x имеют тип double, а мне нужен cl_F с полной точностью, а не ограниченный 15 знаками. У библиотеки правило такое: если ты умножаешь число высокой точности на double, то результат — double. И это очень разумно.

annoynimous ★★★★★
() автор топика
Ответ на: комментарий от shty

> очевидно же, того кто этот код писал без тестирования

Исходно в коде было 3.0/8.0, что устраивало, т.к. работали в хардварной double арифметике. Но понадобилось переписать все на arbitrary precision

annoynimous ★★★★★
() автор топика
Ответ на: комментарий от shty

> а что, хороший подход, давайте теперь под Ваш кривой генератор поменяем весь язык

Язык уже с родовым дефектом. И да, я таки считаю, что нужно это поменять.Хотя все метасимволы все равно уже заняты...

annoynimous ★★★★★
() автор топика
Ответ на: комментарий от annoynimous

>Язык уже с родовым дефектом. И да, я таки считаю, что нужно это поменять.Хотя все метасимволы все равно уже заняты...

Абсолютно то же самое по стандарту и в обычных сях и в фортране. Так что это не баг, это такая стандартизованная фича для языков низкого уровня.

fool_anon
()
Ответ на: комментарий от annoynimous

Но таки ненависть!

сам виноват, надо было писать генератор нормальный сразу

shty ★★★★★
()
Ответ на: комментарий от annoynimous

> очевидно же, того кто этот код писал без тестирования

Исходно в коде было 3.0/8.0, что устраивало, т.к. работали в хардварной double арифметике. Но понадобилось переписать все на arbitrary precision

хорошо что Вы именно сейчас это упомянули, потому что для решения задачи которую Вы изначально описали:

Господа, посоветуйте, как отучить компилятор понимать выражение

cln::cl_F x;

3/8*x

как

cln::cl_F x;

(3/8)*x = 0*x = 0

Вам были приведены корректные решения

мораль: учитесь правильно спрашивать

shty ★★★★★
()
Ответ на: комментарий от annoynimous

не выеживайтесь понятно, что должно быть написано x*3/8

так лучше не делать, потому что получается, что результат выражения зависит от типа переменной, так например для переменной x типа int, он будет работать некорректно, а так бывает, и часто, потом кто-нибудь будет экстрактить метод и засунет его в темплейт и все радуются, ищут баг

shty ★★★★★
()
Ответ на: комментарий от shty

как понятно из сказанного выше, 3.0/8.0 меня тоже перестало устраивать, потому что неточное представление. Если бы в С++ была возможность сказать компилятору: «не трогай это выражение, пока не поймешь тип всех операндов» или, например, «приведи все составляющие выражения к объемлющему типу», то проблемы бы не было. Впрочем, ладно, я решил проблему, так что считаем, что тема просто повод побрюзжать.

annoynimous ★★★★★
() автор топика
Ответ на: комментарий от annoynimous

как понятно из сказанного выше, 3.0/8.0 меня тоже перестало устраивать, потому что неточное представление.

я ещё с первого раза понял, но если задача стояла именно так, то надо было так и писать изначально

Если бы в С++ была возможность сказать компилятору [..] «приведи все составляющие выражения к объемлющему типу»

я в шоке, если честно

(cln::cl_F)3/8
shty ★★★★★
()
Ответ на: комментарий от annoynimous

Я согласен. Но все же, согласитесь, неприятно, что коммутативность умножения может нарушаться.

да, согласен, но это язык программирования (!) низкого уровня и никто не обещал совпадение применяемой условной записи математических операций с таковыми в рассматриваемой Вами проблемной области

shty ★★★★★
()
Ответ на: комментарий от shty

> (cln::cl_F)3/8

Это все костыли, увеличивающие объем вычислений. Понятно же, что умножение двух длинных чисел дороже, чем умножение длинного числа на маленькое целое. Это не считая еще аллокации место под новое длинное и конвертацию. Не, эти шутки были отметены сразу.

annoynimous ★★★★★
() автор топика
Ответ на: комментарий от annoynimous

Это все костыли, увеличивающие объем вычислений.

о как

Понятно же, что умножение двух длинных чисел дороже, чем умножение длинного числа на маленькое целое.

если делать столбиком - да

shty ★★★★★
()
Ответ на: комментарий от shty

да, согласен, но это язык программирования (!) низкого уровня и никто не обещал совпадение применяемой условной записи математических операций с таковыми в рассматриваемой Вами проблемной области

Это еще что, я могу другой анекдот на С++ рассказать: есть такая библиотека mpfr++, так в ней x*y, где x — double, а y — bigfloat получается типом double, потому что компилятор вычисляет его как

x*y.operator double(),
в то время как y*x — bigfloat, т.к. вычисляется как
y.operator*(double x)

annoynimous ★★★★★
() автор топика
Ответ на: комментарий от shty

> если делать столбиком - да

учитывая, что умножать на целое можно вообще сложениями... не вижу point в Вашем высказывании. Даже если умножать по Карацубе или Штрассену, все равно скорее всего умножение на 3 сделается быстрее :)

annoynimous ★★★★★
() автор топика
Ответ на: комментарий от annoynimous

Это еще что, я могу другой анекдот на С++ рассказать: есть такая библиотека mpfr++, так в ней x*y, где x — double, а y — bigfloat получается типом double, потому что компилятор вычисляет его как

Вы математик по образованию?

вынужден повторить: С++ - это язык программирования (!) низкого уровня и никто не обещал совпадение применяемой условной записи математических операций с таковыми в рассматриваемой Вами проблемной области

shty ★★★★★
()
Ответ на: комментарий от shty

> Вы математик по образованию?

Почти.

вынужден повторить: С++ - это язык программирования (!) низкого уровня и никто не обещал совпадение применяемой условной записи математических операций с таковыми в рассматриваемой Вами проблемной области

Странно, выглядит как утка, ходит как утка, ан нет, все же не утка :)

Я знаю про отличие машинной арифметики от «обычной», но надо признать, что гибкость языка C++ настолько велика, что способна порождать неожиданные, а главное трудно уловимые эффекты помимо особенностей машинного представления чисел. И я привожу примеры как раз для того, чтобы обратить внимание на проблему тех, кто понимает причину ее появления, но на практике с таким не сталкивался.

annoynimous ★★★★★
() автор топика
Ответ на: комментарий от annoynimous

я могу другой анекдот на С++ рассказать

и да, чтобы лучше понимать «анекдоты» на С++ рекомендую открыть книжку «язык программирования С» Кернигана и Ричи и прочитать параграф А6.5 про арифметически преобразования

shty ★★★★★
()
Ответ на: комментарий от shty

> и да, чтобы лучше понимать «анекдоты» на С++ рекомендую открыть книжку «язык программирования С» Кернигана и Ричи и прочитать параграф А6.5 про арифметически преобразования

Я все это читал. А вот Вы сути анекдота не поняли: проблема в том, что человек (разработчик mpfr++) определил избыточную (неоднозначную грамматику), а C++ тихо схавал это и теперь выдает не правильный ответ, а претензию на него.

annoynimous ★★★★★
() автор топика
Ответ на: комментарий от annoynimous

гибкость языка C++ настолько велика, что способна порождать неожиданные, а главное трудно уловимые эффекты помимо особенностей машинного представления чисел

вынужден Вас поправить, в данном случае речь идёт не о гибкости, а о том что язык низкоуровневый, я языке Си точно такие же грабли

И я привожу примеры как раз для того, чтобы обратить внимание на проблему тех, кто понимает причину ее появления, но на практике с таким не сталкивался.

а вот тут спасибо :)

shty ★★★★★
()
Ответ на: комментарий от annoynimous

А вот Вы сути анекдота не поняли: проблема в том, что человек (разработчик mpfr++) определил избыточную (неоднозначную грамматику), а C++ тихо схавал это и теперь выдает не правильный ответ, а претензию на него.

я суть данного случая понял, но практическая сторона дела состоит в том что при разработке подобных библиотек, необходимо доказывать корректность функционирования

и да, это проблема не языка, но человека

shty ★★★★★
()
Ответ на: комментарий от annoynimous

Но за указание спасибо, память освежу.

на всякий случай, алгоритм там простой:

1) если один из типов long double - все приводятся к long double

2) если один из типов double - все приводятся к double

...

как видите уже на втором пункте сработало правило и, естественно, значение «y» привелось к double

//объяснить это просто, а вот ловили небось с матюками

shty ★★★★★
()
Ответ на: комментарий от shty

В mpfr++, как я понимаю, случилось вот что:

Если первый аргумент — пользовательский тип, то ищется (перегруженный) оператор-член класса, принимающий один аргумент. Так работает, например y*x: y.operator*(const double x). Далее, если первый аргумент — встроенный тип, а второй пользовательский, то ищется перегрузка оператора operator*() в виде внешней функции, т.е. friend operator(const double x, const bignum& y). С другой стороны, под сигнатуру x*y подходит оператор, у которого оба аргумента — double, т.к. в классе оказался еще определен оператор приведения типа operator double(const bignum& y), так что получилась неоднозначность...

annoynimous ★★★★★
() автор топика
Ответ на: комментарий от annoynimous

В mpfr++, как я понимаю, случилось вот что:

в точечности так :)

shty ★★★★★
()
Ответ на: комментарий от annoynimous

А, нет, похоже я нагнал. Посмотрел сейчас *.h, перегрузки operator*() в форме внешней функции нет, это я перепутал с '-'. Так что работает всё, видимо, так как задумано, но не так как ожидается наивным пользователем вроде меня :)

annoynimous ★★★★★
() автор топика
Ответ на: комментарий от annoynimous

Посмотрел сейчас *.h, перегрузки operator*() в форме внешней функции нет

уточняю: это Вы в mpfr++ посмотрели?

кстати, вот есть неплохой faq по теме

shty ★★★★★
()
Ответ на: комментарий от shty

ну да, в исходник.

mpfr++ меня прельстил тем, что сразу же собрался на моей машине, чего не скажешь о mpfrcpp. Я не настолько подкован в autotools, чтобы разбираться с причинами, поэтому пришлось отказаться. Потом я набрел на cln, у которой есть то преимущество, что она существует в CentOS, под которой наши рабочие машины, так что пришлось менять mpfr++на cln. Впрочем, на моих задачах они работают примерно одинаково хорошо, плохо только то, что в cln мало спецфункций.

За FAQ спасибо, схоронил в букмарках.

annoynimous ★★★★★
() автор топика
Ответ на: комментарий от catap

нет. 1.0 — неточное представление в понимании библиотеки, поэтому она превратит его в bigfloat с 15 знаками. ТОгда уж

cln::cl_float(1)* // Создать bigfloat с умолчальной точностью из 1
3/8*x
но это лишний вызов, плюс долгое умножение длинного (1.0L) на x. В этом смысле запись
3*x/8
более экономная

annoynimous ★★★★★
() автор топика
Ответ на: комментарий от Deleted

Я вас тоже люблю, мальчики :)

В Scheme, кстати, деление двух целых создает дробь. И за это я ее люблю

annoynimous ★★★★★
() автор топика

>Вообще что это: выкрутасы компилятора или непродуманный синтаксис языка (shift/reduce conflict)? Класс, с которым такое происходит — cln::cl_F — взят из библиотеки cln (Class Library for Numbers)

Вообще это кривые руки твоих предшественников — быдлокодеров.

ttnl ★★★★★
()
Ответ на: комментарий от ttnl

> Вообще это кривые руки твоих предшественников — быдлокодеров.

Мсье весь в белом, люблю таких красивых :)

annoynimous ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.