Я работаю со звуковыми данными. Я хотел бы воспроизвести образец файла в обратном порядке. Данные хранятся как беззнаковые целые и упакованы хорошо и плотно. Есть ли способ вызвать memcpy
, который будет копировать в обратном порядке. т. е. если бы у меня было 1,2,3,4, хранящихся в массиве, мог бы я вызвать memcpy
и волшебным образом поменять их местами, чтобы получить 4,3,2,1.
C memcpy в обратном порядке
comment
В C нет такой функции, но ее очень легко написать.
- person Alok Singhal   schedule 11.02.2010
comment
Возможно, стоит подумать об изменении того, как вы перебираете данные, а не об изменении порядка, я подозреваю, что это было бы более эффективно...
- person Mark Elliot   schedule 11.02.2010
comment
Вы поставили меня в тупик волшебным образом.
- person Craig McQueen   schedule 11.02.2010
comment
Марк, я не итерирую, я копирую буферы кусками. Крейг, компьютеры - это магия, верно? :)
- person Aran Mulholland   schedule 11.02.2010
comment
Компьютеры могут быть очень крутыми, что, я думаю, является грубым приближением к магии для некоторых целей. :-)
- person Craig McQueen   schedule 11.02.2010
comment
вы заметили волшебный тег? я даже не добавляла...
- person Aran Mulholland   schedule 11.02.2010
comment
Вы имеете в виду архитектуру процессора и размер буфера? Они могут повлиять на алгоритм. Например, x86 со 128-битными буферами немного отличается от x64 со 128-битными буферами. А ARM с NEON может использовать другой алгоритм, чем x86/x64. Буферы уникальны или вы можете работать на месте? 128-битный буфер немного отличается от 256-битного или 512-битного буфера на x86/x64 из-за AVX. И фиксированный буфер отличается от неизвестного или произвольного размера буфера.
- person jww   schedule 10.04.2017
Ответы (2)
Это работает для копирования int
s в обратном порядке:
void reverse_intcpy(int *restrict dst, const int *restrict src, size_t n)
{
size_t i;
for (i=0; i < n; ++i)
dst[n-1-i] = src[i];
}
Как и memcpy()
, области, на которые указывают dst
и src
, не должны перекрываться.
Если вы хотите изменить на месте:
void reverse_ints(int *data, size_t n)
{
size_t i;
for (i=0; i < n/2; ++i) {
int tmp = data[i];
data[i] = data[n - 1 - i];
data[n - 1 - i] = tmp;
}
}
Обе вышеуказанные функции являются портативными. Возможно, вы сможете ускорить их, используя аппаратно-зависимый код.
(Я не проверял код на правильность.)
person
Alok Singhal
schedule
11.02.2010
какова эффективность этого по сравнению с memcpy?
- person Aran Mulholland; 11.02.2010
memcpy
должно быть O(n), как и эта функция reverse_memcpy
.
- person dreamlax; 11.02.2010
При моем быстром тестировании с
-O3
оптимизацией reverse_memcpy()
примерно в 3 раза медленнее, чем memcpy()
при копировании 1000000 байт. Для 10 000 итераций с 1 000 000 байт memcpy()
заняло 4 секунды, а reverse_memcpy()
— 11. Но эти цифры для очень конкретного случая, так что вы можете проверить сами. Конечно, как сказал Dreamlax, оба являются O (n).
- person Alok Singhal; 11.02.2010
Это тоже неправильно; если исходные данные выборки представлены целыми числами без знака, это также изменит их на байты.
- person Andrew McGregor; 11.02.2010
@Андрей, да. Фиксация. Спасибо!
- person Alok Singhal; 11.02.2010
Замедление, вероятно, связано с тем, что ваши операции чтения и записи не выровнены.
memcpy
, вероятно, работает быстрее, копируя выровненные фрагменты памяти (когда это возможно).
- person dreamlax; 11.02.2010
Вышеупомянутое просто сломано. К тому времени, когда петля достигнет половины пути, вторая половина будет перезаписана перевернутой первой половиной. 1,2,3,4 не станут 4,3,2,1, а на самом деле будут 1,2,2,1. Нужно добавить чтение с конца и чтение с начала, поменять местами, а затем записать значения обратно.
- person mP.; 11.02.2010
@mP -
memcpy
будет иметь тот же результат, так как предполагает, что два указателя не перекрываются, и оптимизирован на этом предположении. Стандартная библиотека memmove
используется в конкретном случае, когда два указателя могут указывать на перекрывающееся пространство. Если OP хочет поведения, подобного memmove
, он должен указать это. Если ОП хочет обратного поведения на месте, он также должен указать это, поскольку этот случай может быть оптимизирован.
- person Chris Lutz; 11.02.2010
@mP: я понял, что ОП может захотеть изменить ситуацию на месте. Я редактировал свой пост, когда вы оставили комментарий. Согласен с вашей точкой зрения полностью. В первом выпуске моего ответа было предупреждение о необходимости непересекающихся регионов и использовании ключевого слова
restrict
в C99...
- person Alok Singhal; 11.02.2010
@Alok: я заметил, что вы отредактировали ответ, но похоже, что OP действительно хочет решения, при котором буфер копируется и реверсируется.
- person dreamlax; 11.02.2010
@dreamlax: да, я тоже так прочитал вопрос, но на всякий случай отредактировал его. Спасибо за ваши комментарии.
- person Alok Singhal; 11.02.2010
@Aran, memcpy и эти обратные функции выполняют разные операции, поэтому сравнение эффективности совершенно бессмысленно. Либо вам нужно его перевернуть, тогда вам нужно написать свою собственную функцию и сравнить ее различные реализации, когда вы обнаружите, что она слишком медленная. Или вам не нужно его переворачивать, тогда просто используйте memcpy или memmove.
- person Secure; 11.02.2010
Первая версия выиграла бы от
restrict
аргументов.
- person Alexandre C.; 25.05.2015
@АлександрК. согласованный. Тем более, что это не работает, если аргументы перекрываются.
- person Alok Singhal; 25.05.2015
Вы можете упростить код на месте с помощью двух переменных:
void reverse_ints(int *data, size_t n) { if (n < 2) return; for (size_t i=0, j=n-1; i < j; ++i, --j) { int tmp = data[i]; data[i] = data[j]; data[j] = tmp; } }
- person Jonathan Leffler; 26.05.2015
@JonathanLeffler, конечно. Есть много способов написать этот цикл.
- person Alok Singhal; 26.05.2015
Я никогда особо не задумывался об измерении производительности реализации memcpy с помощью временной сложности. Это не правильный инструмент для работы. Почти все мы можем согласиться с тем, что O(n) всегда будет иметь место, если только что-то не пошло не так! Выполнение параллельных тестов с различными наборами данных в равных условиях — это то, что нужно.
- person nuzzolilo; 12.06.2016
Я хочу что-то с эффективностью
memcpy
. Учитывая кэши памяти, SSE и тому подобное, это решение будет медленным. И, как говорит Нуццолило, вопрос здесь не в большом О.
- person sudo; 06.03.2017
@Nuzzolilo - Что касается тестов, определенно согласен. Я ищу переносимый шаблон, который компиляторы, такие как Clang, GCC, ICC и MSVC, распознают для создания кода, специфичного для архитектуры, например SSE2 (128-битные буферы), NEON (128-битные буферы), AVX (256-битные буферы) и AVX-512 (512-битные буферы).
- person jww; 10.04.2017
Нет, memcpy не сделает этого в обратном порядке. Если вы работаете на C, напишите для этого функцию. Если вы действительно работаете на C++, используйте std::reverse или std::reverse_copy.
person
janm
schedule
11.02.2010
Я знаю, что это старо, но не могли бы вы опубликовать пример функции, которая это делает? Это просто, но может кому поможет.
- person Austin Mullins; 17.07.2014