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)


[#]  
Love5an

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

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

()
[#] Ответ на: комментарий от Love5an 05.11.2010 2:43:06  

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

***** ()
[#]  

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

***** ()
[#] Ответ на: комментарий от annoynimous 05.11.2010 2:50:44  
Love5an

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

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

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

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

()
[#]  

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

***** ()
[#]  
shty

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

>>-----Цитата---->>

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

cln::cl_F x;

x*(3/8)
<<-----Цитата----<<

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

3.0/8*x

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

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

*** ()
[#] Ответ на: комментарий от annoynimous 05.11.2010 2:48:09  
shty
>>-----Цитата---->>

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

<<-----Цитата----<<

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

*** ()
[#] Ответ на: комментарий от annoynimous 05.11.2010 2:50:44  
shty
>>-----Цитата---->>

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

<<-----Цитата----<<

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

*** ()
[#] Ответ на: комментарий от annoynimous 05.11.2010 2:50:44  

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

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

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

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

* ()
[#]  
aho

> Переписывать код как
> x*(3/8)


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

()
[#] Ответ на: комментарий от aho 05.11.2010 3:33:52  
shty
>>-----Цитата---->>

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

<<-----Цитата----<<

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

*** ()
[#]  
record

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

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

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

?

**** ()
[#]  

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

***** ()
[#] Ответ на: комментарий от catap 05.11.2010 2:57:04  

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

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

***** ()
[#] Ответ на: комментарий от shty 05.11.2010 3:17:51  

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

***** ()
[#] Ответ на: комментарий от shty 05.11.2010 3:18:44  

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

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

***** ()
[#] Ответ на: комментарий от shty 05.11.2010 3:19:49  

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

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

***** ()
[#] Ответ на: комментарий от annoynimous 05.11.2010 5:21:41  
fool_anon

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

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

# ()
[#] Ответ на: комментарий от annoynimous 05.11.2010 5:16:29  
shty
>>-----Цитата---->>

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

<<-----Цитата----<<

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

*** ()
[#] Ответ на: комментарий от annoynimous 05.11.2010 5:20:23  
shty
>>-----Цитата---->>

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

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

<<-----Цитата----<<

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

>>-----Цитата---->>

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

cln::cl_F x;

3/8*x

как

cln::cl_F x;

(3/8)*x = 0*x = 0
<<-----Цитата----<<

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

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

*** ()
[#] Ответ на: комментарий от annoynimous 05.11.2010 5:19:17  
shty
>>-----Цитата---->>

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

<<-----Цитата----<<

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

*** ()
[#] Ответ на: комментарий от shty 05.11.2010 6:08:59  

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

***** ()
[#] Ответ на: комментарий от shty 05.11.2010 6:13:37  

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

***** ()
[#] Ответ на: комментарий от annoynimous 05.11.2010 6:15:13  
shty
>>-----Цитата---->>

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

<<-----Цитата----<<

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

>>-----Цитата---->>

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

<<-----Цитата----<<

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

(cln::cl_F)3/8
*** ()
[#] Ответ на: комментарий от annoynimous 05.11.2010 6:19:38  
shty
>>-----Цитата---->>

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

<<-----Цитата----<<

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

*** ()
[#] Ответ на: комментарий от shty 05.11.2010 6:21:21  

> (cln::cl_F)3/8

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

***** ()
[#] Ответ на: комментарий от annoynimous 05.11.2010 6:24:50  
shty
>>-----Цитата---->>

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

<<-----Цитата----<<

о как

>>-----Цитата---->>

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

<<-----Цитата----<<

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

*** ()
[#] Ответ на: комментарий от shty 05.11.2010 6:23:49  

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

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

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

***** ()
[#] Ответ на: комментарий от shty 05.11.2010 6:28:09  

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

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

***** ()
[#] Ответ на: комментарий от annoynimous 05.11.2010 6:30:58  
shty
>>-----Цитата---->>

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

<<-----Цитата----<<

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

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

*** ()
[#] Ответ на: комментарий от shty 05.11.2010 6:38:10  

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

Почти.

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

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

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

***** ()
[#] Ответ на: комментарий от annoynimous 05.11.2010 6:30:58  
shty
>>-----Цитата---->>

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

<<-----Цитата----<<

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

*** ()
[#] Ответ на: комментарий от shty 05.11.2010 6:44:18  

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

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

***** ()
[#] Ответ на: комментарий от annoynimous 05.11.2010 6:43:54  
shty
>>-----Цитата---->>

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

<<-----Цитата----<<

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

>>-----Цитата---->>

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

<<-----Цитата----<<

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

*** ()
[#] Ответ на: комментарий от shty 05.11.2010 6:44:18  

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

***** ()
[#] Ответ на: комментарий от annoynimous 05.11.2010 6:46:42  
shty
>>-----Цитата---->>

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

<<-----Цитата----<<

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

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

*** ()
[#] Ответ на: комментарий от annoynimous 05.11.2010 6:49:30  
shty
>>-----Цитата---->>

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

<<-----Цитата----<<

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

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

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

...

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

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

*** ()
[#] Ответ на: комментарий от shty 05.11.2010 6:56:59  

В 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 05.11.2010 7:07:02  
shty
>>-----Цитата---->>

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

<<-----Цитата----<<

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

*** ()
[#] Ответ на: комментарий от annoynimous 05.11.2010 7:07:02  

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

***** ()
[#] Ответ на: комментарий от annoynimous 05.11.2010 7:12:21  
shty
>>-----Цитата---->>

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

<<-----Цитата----<<

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

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

*** ()
[#] Ответ на: комментарий от shty 05.11.2010 7:22:30  

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

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

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

***** ()
[#] Ответ на: комментарий от annoynimous 05.11.2010 5:18:34  

((cln::cl_F)1.0) * 3/8 * x

не?

***** ()
[#] Ответ на: комментарий от catap 05.11.2010 13:38:39  

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

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

***** ()
[#] Ответ на: комментарий от annoynimous 05.11.2010 2:48:09  
mironov_ivan
>>-----Цитата---->>

Кого бы убить за это...

<<-----Цитата----<<

Себя.

***** ()
[#] Ответ на: комментарий от mironov_ivan 05.11.2010 15:09:28  

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

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

***** ()
[#]  
ttnl

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

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

**** ()
[#] Ответ на: комментарий от ttnl 05.11.2010 15:37:45  

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

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

***** ()