| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > Преобразование double в __int64 |
| Автор: Katshooter 15.12.2008, 20:28 | ||
| Приветик всем))) ПОМОГИТЕ ПЛИЗ!!! Нужно преобразовать double в __int64 без потери данных Явным преобразованием типа:
теряю данные.... может есть какая-нить сишная функция...??? а, еще проблемка, это нада сделать на Си... |
| Автор: Rififi 15.12.2008, 20:41 |
| Katshooter, Нужно преобразовать double в __int64 без потери данных поясни глубинный смысл этой фразы. |
| Автор: Katshooter 15.12.2008, 20:49 |
| ))) сори, ну например double 12345672903000000+11E (в таком виде приходят данные), при при явном приведении получаем 12345672 (а ...903 округляются) |
| Автор: Rififi 15.12.2008, 20:59 |
| Katshooter, у тебя явно имеется талант к исчерпывающему и предельно понятному объяснению, однако. :gigi: |
| Автор: Void 15.12.2008, 21:06 | ||
Кастуя телепатию, предполагаю, что требуется просто положить содержимое double в int64 побитово.
Хотя бред конечно. Но никакого другого способа всегда сохранить точное значение нет, fixed point тоже не катит. |
| Автор: Katshooter 15.12.2008, 21:39 |
| спасибо) буду пробовать))) |
| Автор: Alek86 15.12.2008, 23:03 | ||
насколько я понимаюб, человеку нужно сериализовать double в int64 записать его реально - побитово а вот как обстоят дела с разным представлением double числа на разных платформах (та даже на 2х exe-шках, собранных разными компиляторами), я не знаю. возможно double там представляется совсем по-разному, и тупое побитовое сохранение не приведет ни к чему хорошему |
| Автор: mes 15.12.2008, 23:34 | ||
вот этот набросок каста http://forum.vingrad.ru/index.php?showtopic=239471&view=findpost&p=1721438 "предназначеный" для битового конвертирования с проверкой размера, и он более безопасен чем простое побитовое сохранение, но код приспособленный под одну платформу не будет компилиться на другой. К тому же его в той же теме и заругали, поэтому желаю 7 раз обдумать прежде чем использовать. |
| Автор: J0ker 15.12.2008, 23:38 |
компилятор тут обычно не при чем числа с ПТ хранятся в формате, пригодном для загрузки в FPU целевой платформы |
| Автор: mes 15.12.2008, 23:38 |
на си можно таже сделать подобный макрос который будет проверять размер и предупреждать, если результат не "вписывается" в хранилище. |
| Автор: J0ker 15.12.2008, 23:41 |
во-первых d, а не df во-вторых *((double*)&i) а в третьих это UB насколько я понимаю |
| Автор: Earnest 17.12.2008, 17:54 | ||
Да чего там, если размер одинаков, просто union - старый сишный метод.
Ну и assert на равенство размеров, на всякий случай... И нет там никакого UB. |
| Автор: J0ker 17.12.2008, 20:38 | ||
3.10/15
хотя не совсем понятно, что включает в себя "attempts to access" - но, ИМХО, и запись и чтение |
| Автор: Earnest 18.12.2008, 14:21 |
| Нет, в данном контексте это использование по назначению - т.е. в вычислениях (или в присваивании). И потом, никто не говорит, что UB - это когда программа падает. Это просто значит, что результат получится неизвестно какой. Скажем, целая -1, если ее таким образом преобразовать в double становится Not-a-number. И что там в вычислениях получится - хто знает. Например, если сравнивать NAN с любым числом, то результат стабилен (не помню уже true или false), независимо от того, какое число и какое сравнение. С другой стороны - это не раз наблюдаемое мною поведение наверняка является свойством конкретного компилятора или может даже параметров компиляции (release-debug). А писать-читать в память ты можешь что угодно - была бы память. Это ведь по сути ничем не отличается от memcpy, как предложил Void, только запись яснее (на мой взгляд). Reinterpret_cast биты не портит... Т.е. если ты запихиваешь, скажем float в LPARAM, чтобы послать сообщение, а потом его оттуда извлекаешь обратной операцией, то все совершенно нормально и легально. |
| Автор: J0ker 18.12.2008, 18:43 | ||||
вот тут вы совершенно НЕ правы связано это не с возможностью/невозможностью конкретного преобразования типа, а с оптимизацией дело в том, что компилятор зачастую не в состоянии отследить алиасинг, что может приводить при оптимизации к сайдэффектам например следующий код:
без оптимизации может выдавать "10", а с оптимизацией - "5" если такое случится, и вы посмотрите на оптимизированный ассемблерный код, то сможете заметить странную вещь - printf либо вызывается с константой - совершенно не взирая на реальное значение переменной, либо присвоение происходит после вызова printf Обсуждение подобного эффекта тут: http://www.rsdn.ru/Forum/message/2630988.flat.1.aspx ЗЫЖ да, если что - вышеприведенный пример ессесна не портируем на биг-ендиан будет явная лажа |
| Автор: J0ker 18.12.2008, 19:15 | ||
| да, вот еще 5.17/8
|
| Автор: Earnest 19.12.2008, 09:27 |
| Речь идет совсем не о том, чтобы преобразовать типы и спать спокойно, а том, чтобы сделать это ВРЕМЕННО. Если ты собираешься запихнуть double в int64, а потом пользоваться этим int'ом, то да, это не безопасно. Но если int64 использовать как временное хранилище для битов дабла, то ничего с твоим даблом не случится. А твой пример с printf вообще из другой оперы. |
| Автор: J0ker 19.12.2008, 18:40 |
| ну не знаю... надо анрила спросить... что-то мне кажется формально это подподает под UB |
| Автор: GoldFinch 19.12.2008, 20:18 |
| где это уже обсуждалось, толко речь шла о float так вот в переменную размером N байт можно запихнуть любую другую переменную N байт и ничего с ней не случиться. |
| Автор: UnrealMan 19.12.2008, 20:49 | ||
| Начнём с того, что в стандарте C++ нету встроенного типа __int64 Далее, т.к. стандарт не обязывает double иметь не более строгие требования к выравниванию, чем __int64, то результат reinterpret_cast-а из __int64 * в double * - unspecified.
Отличается. На некоторых архитектурах несоблюдение выравнивания приводит к аппаратному исключению. Так что memcpy надёжнее. |
| Автор: J0ker 19.12.2008, 21:51 |
| UnrealMan, а конкретно под 3.10/15 и 5.17/8 это подпадает? |
| Автор: UnrealMan 19.12.2008, 23:41 |
Под 3.10/15 подпадает, под 5.17/8 - нет. |
| Автор: Earnest 22.12.2008, 14:22 | ||
Возможно, в случае с выравниванием и да. Но если я заведу union как предлагала, с обоими этими типами - согласись, все должно быть ок. Хотя, конечно, не факт, что тогда размер юниона будет равен размеру double. Но это уже поддается контролю при сборке. Кроме того, в жизни такого не встречала (разницы в выравнивании). Конечно, на какой-то отдельно взятой и не очень распростаненной платформе - наверное, возможно. Но человек, который на ней програмирует, видимо, должен это знать. А код, который пишется под широко распросраненные платформы вряд ли кто-то расчитывает перенести на какие-то специальные, не прикладывая специальных усилий. Так что все эти рассуждения очень похожи на теоретическую опастность попасть под кирпич, прогуливаясь по улице. |
| Автор: UnrealMan 22.12.2008, 15:45 | ||
По стандарту нет (см. 3.10/15), но с практической точки зрения, скорее всего, да (если размер double не превышает 64 бит). Другое дело, что непонятно, зачем это нужно - переводить double в __int64 и обратно. |
| Автор: J0ker 22.12.2008, 23:20 | ||||||
разве это не разрешает делать это через union?:
|
| Автор: UnrealMan 23.12.2008, 07:44 |
Прочитай внимательно правило целиком. |
| Автор: Earnest 23.12.2008, 13:16 | ||
Если речь о конвертации, а выравнивание неодинаковое (или что-то еще неодинаковое), то обмен через union действительно некорректен - нет гарантии, что все биты будут общими. Корректно только само присваивание. Поскольку union должен быть выделен так, чтобы все комфортно разместились. Я имела в виду именно это.
Ну, скажем, чтобы передать параметр процедуре, принимающей исключительно int64. Реальный пример (здесь правда речь идет o паре float\DWORD) - послать сообщение с параметром float (притом что там есть только DWORD параметры). |
| Автор: UnrealMan 23.12.2008, 17:09 | ||
Ну, если процедура изначально написана через ж., и альтернативы её использованию нет, то тут всё понятно. В норме же аргументы неизвестных типов передаются через указатели void * или char *, а не запихиваются в целочисленные объекты. |
| Автор: GoldFinch 23.12.2008, 19:07 |
| UnrealMan, а нафига создавать переменную в которой будет храниться это значение, вычислять указатель на это значение, если можно просто передать его по значению? |
| Автор: UnrealMan 23.12.2008, 20:30 | ||
Во-первых, вводить дополнительную переменную нужно только тогда, когда имеется rvalue, к которому нельзя применить операцию взятия адреса. Во-вторых, объекты целочисленного типа предназначены для хранения целых чисел или наборов флагов, а запихивание в них значений объектов произвольных типов - это использование средств языка не по назначению (точно так же, как забивание шурупов кувалдой - использование кувалды не по назначению). От такого использования страдает как минимум самодокументирумость кода. Этот способ плохо масштабируется. Представим, что спустя некоторое время понадобилось добавить возможность передачи в функцию не только double-значений, но и long double-значений, не вмещающихся в 64 бита. Что делать в таком случае? Придётся передавать значение другим способом. Теряем единообразие. В-третьих при использовании void * пользователю функции не нужно захламлять код reinterpret_cast-ами для передаваемых аргументов. |
| Автор: GoldFinch 23.12.2008, 21:00 | ||
не выходите из контекста задачи Есть функция которая принимает восемь байт (qwоrd он же int64) мы в эти 8 байт можем запихнуть *чтоугодно* что влезет в 8 байт, а в тех редких случаях когда не влезет, мы передаем указатель на это значение, 8 байт хватит практически на любой указатель. Так или иначе, вне зависимости от вашего желания такие функции существуют - GetMessage, CreateThread, и т.п. То что в С++ для такого надо городить reinterpret_cast'ы и другие многобуквенные операторы - это проблема языка С++ которая никак не связана с задачей. Код куда надо передавать эти 8 байт может быть написан на любом ЯП, причем разработчик этого кода мог и не задумываться что ктото будет вызывать этот код в модуле на С++ |
| Автор: J0ker 23.12.2008, 21:46 | ||||
это проблема интерфейса, сделаного кривыми руками
а как вы будете этот код вызывать? наверное создадите интерфейс? так вот интерфейс надо делать прямыми руками |
| Автор: GoldFinch 23.12.2008, 22:09 |
| ну и как сделать интерфейс к такой функции? |
| Автор: UnrealMan 23.12.2008, 22:30 | ||||
А не проще ли всегда передавать указатель и не парить пользователю мозги магическим ограничением в 8 байт?
Можно подумать, в других строготипизированных языках подобные преобразования не нужны. |
| Автор: J0ker 23.12.2008, 22:34 |
| включаю телепатию и определяю, что это за "такая" функция |
| Автор: mes 23.12.2008, 22:42 | ||
|
| Автор: UnrealMan 23.12.2008, 22:56 |
| А что там не так с этими функциями? |
| Автор: GoldFinch 23.12.2008, 23:11 | ||
если в 95% случаев хватает 8 байт то не проще более того, не всегда есть возможность передать указатель на переменную вместо значения переменной например в thread указатель на локальную переменную можно передать только если эа локальная переменная будет существовать, в sendmessage можно передать указатель только если это сообщение отправляется своему окну, и т.д. |
| Автор: UnrealMan 23.12.2008, 23:42 | ||||
Спорно. Увеличение способов передачи значений предрасполагает к совершению ошибок.
Что-то я вообще не понял, где тут проблемы с передачей указателя. Кроме того, если сильно не нравится заводить переменные для сохранения значений rvalue-выражений, то можно воспользоваться шаблоном
|
| Автор: Earnest 24.12.2008, 16:39 |
| UnrealMan, шаблон или прочие ухищрения - это если ты сам проектируешь интерфейс. Тогда да, не надо никаких вывертов и параметры нужны ровно такие, какие нужны. А вот если ты используешь чужой интерфейс (операционной системы, библиотеки, etc), и он говорит: "только DWORD" или "LPVOID". А тебе нужно float... Можно и указатель. Если, конечно, мы остаемся в рамках процесса. И при этом нужно гарантировать существование этого объекта (переменной), когда сообщение будет обрабатываться. А оно вовсе не обязано быть синхронным. И т.д. Короче, ситуаций, когда проще использовать имеющиеся биты и не разводить лишний геморрой ради 4-8 байтов - предостаточно. И никакой это не изврат: ты скажи об этом C-программистам. Просто нужно "уметь их готовить". |
| Автор: UnrealMan 24.12.2008, 17:26 | ||||||||
По этому поводу я уже высказался:
Что мешает сохранить значение объекта, на который указывает переданный указатель, до возврата управления функцией?
Я не знаю ни одной. Изврат. По причинам, изложенным выше. Кто сказал, что из подвальных крыс нельзя приготовить замечательный ужин? Просто нужно "уметь их готовить". Приятного аппетита |
| Автор: mes 24.12.2008, 17:56 |
http://www.privatwein.de/ebay/Set_Turm_02_PX400x464dpi144.jpg перевод слов на обложках : филе из крыс, мясо медведя, лягушачьи лапки |
| Автор: GoldFinch 24.12.2008, 19:02 |
| Earnest, +1 UnrealMan, кроме С++ есть много других языков программирования, с точки зрения которых ваш код на С++ может показаться написанным "через ж." если вы чегото не знаете это значит что вы это не знаете, а не то что это не существует >Что мешает сохранить значение объекта, на который указывает переданный указатель, до возврата управления функцией? - то что его надо хранить неопределенно долго - то что значение надо передать в адресное пространство другого процесса - ... |
| Автор: Earnest 24.12.2008, 19:31 | ||
Да вы, батенька, идеалист... Знаешь, сколько код живет? И не надо так высокомерно "через ж.": концепции в программировании меняются быстрее, чем ты можешь себе представить: "кошерное" поведение вчера и сегодня - две большие разницы. Это связано как с развитием над-языковых метафор, так и, не в последнюю очередь, с ростом производительности машин: сейчас можно себе позволить то, на чем вчера приходжилось экономить.
Какого возврата? Есть асинхронная передача, есть другие процессы... впрочем, уже говорили... Я могу придумать массу способов как организовать такое безопасное хранение\передачу, если по-другому никак. Но если достаточно запихать float в 4-байтовый int - неужели я буду городить этот огород? Время можно потратить более интересно. Ты на чистом C не программировал никогда? Можно упираться до посинения: это говорит только о недостатке опыта. Реальный программист работает в реальной ситуации, а не в идеальной. Насчет крыс тоже пример так себе. Читаем Фарли Моуэта - ему понравилось. Правда там крысы были не подвальные, а полевые, но с моей точки зрения разница не велика. |
| Автор: UnrealMan 24.12.2008, 22:40 | ||||||||
Очень странное заявление.
Мне достаточно того, что вероятность существования этого чего-то очень мала (до тех пор, пока кто-либо не предоставит весомых аргументов считать иначе).
Я не вижу в этих пунктах никаких препятствий. Ошибаешься. Я материалист Зачастую больше, чем хотелось бы. Не нужно путать продолжительность жизни кода и его качество. Пока функция не вернёт управление, временный объект в примере выше или тем более локальный объект, адрес которого также может быть передан в функцию, гарантированно существует. Ну, есть, и что дальше?
Какой такой огород? Покажи на конкретных примерах, что с чем сравнивается. |
| Автор: GoldFinch 25.12.2008, 12:53 | ||||
чтобы передать указатель в чужое АП этот указатель должен указывать на переменную в чужом АП, а создать переменную в чужом АП - не самая тривиальная задача, более того, зачастую это впринципе невозможно
асинхронные функции сначала возвращают управление, а потом используют переданные им объекты, вы не знали? |
| Автор: mes 25.12.2008, 13:00 | ||
клонируя при этом нужные из переданных данных, и удаляя последние, когда они им станут не нужны. (в нормальных условиях) |
| Автор: GoldFinch 25.12.2008, 14:06 |
| mes, так ведь не везде такое предусмотрено |
| Автор: UnrealMan 25.12.2008, 14:33 | ||
Как реализация межпроцессного взаимодействия связана со способом передачи значения в исходную функцию?
Переданные объекты никогда не используются асинхронно, вместо них всегда используются копии объектов. |
| Автор: GoldFinch 25.12.2008, 15:32 |
| UnrealMan, да с чего вы взяли что всегда копии? в CreateThread, CreateRemoteThread, SendMessage - не копии |
| Автор: mes 25.12.2008, 15:43 | ||||
а с чего Вы взяли что эта функция асинхроннaя ?? (также как и две другие)
Может имелось ввиду PostMessage. Вот она асинхронная, но и копирует данные.
|
| Автор: GoldFinch 25.12.2008, 16:00 |
| пусть не асинхронная, но в SendMessage параметры сообщения передаются окну без копирования, если в lparam указатель на переменную - никто не скопирует эту переменную |
| Автор: UnrealMan 25.12.2008, 16:42 |
Если параметры функции - не ссылки, то по-другому быть не может |
| Автор: mes 25.12.2008, 17:33 | ||
Ну и где Вы видите проблему ? При отсылке между потоками ? Так там нельзя использовать эту функцию При пользовании окном этого указателя, в следующем цикле ? так если окну нужны данные, оно должно сохранить их , а не указатель. |
| Автор: UnrealMan 25.12.2008, 18:36 | ||
Как это нельзя? |
| Автор: mes 25.12.2008, 18:45 |
ошибся.. ( Хотя сути не меняет. ) |
| Автор: J0ker 25.12.2008, 19:03 |
| UnrealMan, кончай морочить детям голову Дети, UnrealMan вам намякивает, что объект самостоятельно может управлять своим жизненным циклом - без привлечения внимания вызывающего кода - вопрос лишь в правильном интерфейсе |