Right shift a binary string efficiently in C++
up vote
-1
down vote
favorite
If I have a string that represents an integer in binary form such as
1101101
and I want to circularly right shift it to obtain
1110110
One way I could think of would be converting the string into an int
and use (taken from wikipedia)
// https://stackoverflow.com/a/776550/3770260
template <typename INT>
#if __cplusplus > 201100L // Apply constexpr to C++ 11 to ease optimization
constexpr
#endif // See also https://stackoverflow.com/a/7269693/3770260
INT rol(INT val, size_t len) ((unsigned) val >> (-len & (sizeof(INT) * CHAR_BIT - 1)));
However, if the string consists of, say, 10^6 char
then this does not work as the integer representation exceeds even the range of __int64
.
In that case I could think of a solution by looping over the string
//let str be a char string of length n
char temp = str[n - 1];
for(int i = n - 1; i > 0; i--)
str[i] = str[i - 1];
str[0] = temp;
This solution runs in O(n)
due the loop over the length of the string, n. My question is, is there much more efficient way to implement circular shifting for large binary strings?
EDIT
Both input and output are std::string
s
c++ runtime bit-shift
|
show 10 more comments
up vote
-1
down vote
favorite
If I have a string that represents an integer in binary form such as
1101101
and I want to circularly right shift it to obtain
1110110
One way I could think of would be converting the string into an int
and use (taken from wikipedia)
// https://stackoverflow.com/a/776550/3770260
template <typename INT>
#if __cplusplus > 201100L // Apply constexpr to C++ 11 to ease optimization
constexpr
#endif // See also https://stackoverflow.com/a/7269693/3770260
INT rol(INT val, size_t len) ((unsigned) val >> (-len & (sizeof(INT) * CHAR_BIT - 1)));
However, if the string consists of, say, 10^6 char
then this does not work as the integer representation exceeds even the range of __int64
.
In that case I could think of a solution by looping over the string
//let str be a char string of length n
char temp = str[n - 1];
for(int i = n - 1; i > 0; i--)
str[i] = str[i - 1];
str[0] = temp;
This solution runs in O(n)
due the loop over the length of the string, n. My question is, is there much more efficient way to implement circular shifting for large binary strings?
EDIT
Both input and output are std::string
s
c++ runtime bit-shift
1
Ever think of using std::rotate?
– PaulMcKenzie
Nov 10 at 0:51
Use astd::deque
instead of astring
if you can.deque
has zounds-fast insert and removal from both ends while still allowing iterating and indexing.
– user4581301
Nov 10 at 0:52
@PaulMcKenzie std::rotate also runs in O(n)
– iambrj
Nov 10 at 0:53
Just keep a pointer to the first bit. O(1).
– stark
Nov 10 at 0:54
Do you need contiguous container ? Else a (circular) string + index should do the job.
– Jarod42
Nov 10 at 0:55
|
show 10 more comments
up vote
-1
down vote
favorite
up vote
-1
down vote
favorite
If I have a string that represents an integer in binary form such as
1101101
and I want to circularly right shift it to obtain
1110110
One way I could think of would be converting the string into an int
and use (taken from wikipedia)
// https://stackoverflow.com/a/776550/3770260
template <typename INT>
#if __cplusplus > 201100L // Apply constexpr to C++ 11 to ease optimization
constexpr
#endif // See also https://stackoverflow.com/a/7269693/3770260
INT rol(INT val, size_t len) ((unsigned) val >> (-len & (sizeof(INT) * CHAR_BIT - 1)));
However, if the string consists of, say, 10^6 char
then this does not work as the integer representation exceeds even the range of __int64
.
In that case I could think of a solution by looping over the string
//let str be a char string of length n
char temp = str[n - 1];
for(int i = n - 1; i > 0; i--)
str[i] = str[i - 1];
str[0] = temp;
This solution runs in O(n)
due the loop over the length of the string, n. My question is, is there much more efficient way to implement circular shifting for large binary strings?
EDIT
Both input and output are std::string
s
c++ runtime bit-shift
If I have a string that represents an integer in binary form such as
1101101
and I want to circularly right shift it to obtain
1110110
One way I could think of would be converting the string into an int
and use (taken from wikipedia)
// https://stackoverflow.com/a/776550/3770260
template <typename INT>
#if __cplusplus > 201100L // Apply constexpr to C++ 11 to ease optimization
constexpr
#endif // See also https://stackoverflow.com/a/7269693/3770260
INT rol(INT val, size_t len) ((unsigned) val >> (-len & (sizeof(INT) * CHAR_BIT - 1)));
However, if the string consists of, say, 10^6 char
then this does not work as the integer representation exceeds even the range of __int64
.
In that case I could think of a solution by looping over the string
//let str be a char string of length n
char temp = str[n - 1];
for(int i = n - 1; i > 0; i--)
str[i] = str[i - 1];
str[0] = temp;
This solution runs in O(n)
due the loop over the length of the string, n. My question is, is there much more efficient way to implement circular shifting for large binary strings?
EDIT
Both input and output are std::string
s
c++ runtime bit-shift
c++ runtime bit-shift
edited Nov 10 at 1:21
asked Nov 10 at 0:47
iambrj
1116
1116
1
Ever think of using std::rotate?
– PaulMcKenzie
Nov 10 at 0:51
Use astd::deque
instead of astring
if you can.deque
has zounds-fast insert and removal from both ends while still allowing iterating and indexing.
– user4581301
Nov 10 at 0:52
@PaulMcKenzie std::rotate also runs in O(n)
– iambrj
Nov 10 at 0:53
Just keep a pointer to the first bit. O(1).
– stark
Nov 10 at 0:54
Do you need contiguous container ? Else a (circular) string + index should do the job.
– Jarod42
Nov 10 at 0:55
|
show 10 more comments
1
Ever think of using std::rotate?
– PaulMcKenzie
Nov 10 at 0:51
Use astd::deque
instead of astring
if you can.deque
has zounds-fast insert and removal from both ends while still allowing iterating and indexing.
– user4581301
Nov 10 at 0:52
@PaulMcKenzie std::rotate also runs in O(n)
– iambrj
Nov 10 at 0:53
Just keep a pointer to the first bit. O(1).
– stark
Nov 10 at 0:54
Do you need contiguous container ? Else a (circular) string + index should do the job.
– Jarod42
Nov 10 at 0:55
1
1
Ever think of using std::rotate?
– PaulMcKenzie
Nov 10 at 0:51
Ever think of using std::rotate?
– PaulMcKenzie
Nov 10 at 0:51
Use a
std::deque
instead of a string
if you can. deque
has zounds-fast insert and removal from both ends while still allowing iterating and indexing.– user4581301
Nov 10 at 0:52
Use a
std::deque
instead of a string
if you can. deque
has zounds-fast insert and removal from both ends while still allowing iterating and indexing.– user4581301
Nov 10 at 0:52
@PaulMcKenzie std::rotate also runs in O(n)
– iambrj
Nov 10 at 0:53
@PaulMcKenzie std::rotate also runs in O(n)
– iambrj
Nov 10 at 0:53
Just keep a pointer to the first bit. O(1).
– stark
Nov 10 at 0:54
Just keep a pointer to the first bit. O(1).
– stark
Nov 10 at 0:54
Do you need contiguous container ? Else a (circular) string + index should do the job.
– Jarod42
Nov 10 at 0:55
Do you need contiguous container ? Else a (circular) string + index should do the job.
– Jarod42
Nov 10 at 0:55
|
show 10 more comments
1 Answer
1
active
oldest
votes
up vote
0
down vote
You have to move memory one way or another, so your proposed solution is as fast as it gets.
You might also use standard std::string
functions:
str.insert(str.begin(), str[n - 1]);
str.erase(str.end() - 1);
or memmove
, or memcpy
(I don't actually recommend this, it's for an argument)
char temp = str[n - 1];
memmove(str.data() + 1, str.data(), n - 1);
str[0] = temp;
Note that memmove
may look faster, but it's essentially the same thing as your loop. It is moving bytes one by one, it's just encapsulated in a different function. This method might be faster for much larger data blocks, of size 1000 bytes or more, since the CPU is optimized to move large chunks of memory. But you won't be able to measure any difference for 10 or 20 bytes.
Moreover, the compiler will most likely run additional optimizations when it sees your for
loop, it realizes that you are moving memory and chooses the best option.
The compiler is also good at dealing with std::string
methods. These are common operations and the compiler knows the best way to handle it.
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
0
down vote
You have to move memory one way or another, so your proposed solution is as fast as it gets.
You might also use standard std::string
functions:
str.insert(str.begin(), str[n - 1]);
str.erase(str.end() - 1);
or memmove
, or memcpy
(I don't actually recommend this, it's for an argument)
char temp = str[n - 1];
memmove(str.data() + 1, str.data(), n - 1);
str[0] = temp;
Note that memmove
may look faster, but it's essentially the same thing as your loop. It is moving bytes one by one, it's just encapsulated in a different function. This method might be faster for much larger data blocks, of size 1000 bytes or more, since the CPU is optimized to move large chunks of memory. But you won't be able to measure any difference for 10 or 20 bytes.
Moreover, the compiler will most likely run additional optimizations when it sees your for
loop, it realizes that you are moving memory and chooses the best option.
The compiler is also good at dealing with std::string
methods. These are common operations and the compiler knows the best way to handle it.
add a comment |
up vote
0
down vote
You have to move memory one way or another, so your proposed solution is as fast as it gets.
You might also use standard std::string
functions:
str.insert(str.begin(), str[n - 1]);
str.erase(str.end() - 1);
or memmove
, or memcpy
(I don't actually recommend this, it's for an argument)
char temp = str[n - 1];
memmove(str.data() + 1, str.data(), n - 1);
str[0] = temp;
Note that memmove
may look faster, but it's essentially the same thing as your loop. It is moving bytes one by one, it's just encapsulated in a different function. This method might be faster for much larger data blocks, of size 1000 bytes or more, since the CPU is optimized to move large chunks of memory. But you won't be able to measure any difference for 10 or 20 bytes.
Moreover, the compiler will most likely run additional optimizations when it sees your for
loop, it realizes that you are moving memory and chooses the best option.
The compiler is also good at dealing with std::string
methods. These are common operations and the compiler knows the best way to handle it.
add a comment |
up vote
0
down vote
up vote
0
down vote
You have to move memory one way or another, so your proposed solution is as fast as it gets.
You might also use standard std::string
functions:
str.insert(str.begin(), str[n - 1]);
str.erase(str.end() - 1);
or memmove
, or memcpy
(I don't actually recommend this, it's for an argument)
char temp = str[n - 1];
memmove(str.data() + 1, str.data(), n - 1);
str[0] = temp;
Note that memmove
may look faster, but it's essentially the same thing as your loop. It is moving bytes one by one, it's just encapsulated in a different function. This method might be faster for much larger data blocks, of size 1000 bytes or more, since the CPU is optimized to move large chunks of memory. But you won't be able to measure any difference for 10 or 20 bytes.
Moreover, the compiler will most likely run additional optimizations when it sees your for
loop, it realizes that you are moving memory and chooses the best option.
The compiler is also good at dealing with std::string
methods. These are common operations and the compiler knows the best way to handle it.
You have to move memory one way or another, so your proposed solution is as fast as it gets.
You might also use standard std::string
functions:
str.insert(str.begin(), str[n - 1]);
str.erase(str.end() - 1);
or memmove
, or memcpy
(I don't actually recommend this, it's for an argument)
char temp = str[n - 1];
memmove(str.data() + 1, str.data(), n - 1);
str[0] = temp;
Note that memmove
may look faster, but it's essentially the same thing as your loop. It is moving bytes one by one, it's just encapsulated in a different function. This method might be faster for much larger data blocks, of size 1000 bytes or more, since the CPU is optimized to move large chunks of memory. But you won't be able to measure any difference for 10 or 20 bytes.
Moreover, the compiler will most likely run additional optimizations when it sees your for
loop, it realizes that you are moving memory and chooses the best option.
The compiler is also good at dealing with std::string
methods. These are common operations and the compiler knows the best way to handle it.
edited Nov 10 at 7:41
answered Nov 10 at 7:00
Barmak Shemirani
20.2k42043
20.2k42043
add a comment |
add a comment |
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53235032%2fright-shift-a-binary-string-efficiently-in-c%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
Ever think of using std::rotate?
– PaulMcKenzie
Nov 10 at 0:51
Use a
std::deque
instead of astring
if you can.deque
has zounds-fast insert and removal from both ends while still allowing iterating and indexing.– user4581301
Nov 10 at 0:52
@PaulMcKenzie std::rotate also runs in O(n)
– iambrj
Nov 10 at 0:53
Just keep a pointer to the first bit. O(1).
– stark
Nov 10 at 0:54
Do you need contiguous container ? Else a (circular) string + index should do the job.
– Jarod42
Nov 10 at 0:55