Overclock.net › Forums › Software, Programming and Coding › Coding and Programming › How would I separate a 3 digit number in C++?
New Posts  All Forums:Forum Nav:

How would I separate a 3 digit number in C++? - Page 2

post #11 of 18
Quote:
Originally Posted by BradleyW View Post

This is great information. Thank you to each and every one of you. thumb.gif

Edit: Once all 3 digits are split up into 3 seperate variables, how would I put all 3 back into a single variable which holds the 3 digit number?
I tried "string number [3] = {n1, n2, n3};" but I have errors under n1, n2 and n3.

Are you trying to use a String object as a C-String array?

If so do this instead:
Code:
string number = to_string(n1) + to_string(n2) + to_string(n3);

This is assuming that you've added the following to the top of your file.
Code:
#include <string>

using namespace std;
Deimos (G4.P)
(18 items)
 
 
Arcturus (G4.S)
(9 items)
 
CPUMotherboardGraphicsRAM
Intel i7 5930K ASUS X99 Deluxe II eVGA Titan X SC 64GB Corsair Vengeance DDR4/2800 
Hard DriveHard DriveHard DriveCooling
Intel 750 400GB Samsung 850 Pro 512GB Samsung 850 Evo 1TB HEATKILLER IV PRO CPU Block 
CoolingOSMonitorKeyboard
HEATKILLER IV XL GPU Block Windows 8.1 Pro Dell P2715Q Corsair K95 RGB 
PowerCaseMouseAudio
Corsair AX860i Silverstone Fortress 2 Silver eVGA TORQ X10 Carbon Denon AVR-S510BT 
AudioAudio
JBL Studio 530 Dayton SUB-120 
CPUMotherboardGraphicsRAM
Intel i5 4670k @ 4.0 Ghz ASUS Z87-PRO eVGA Titan X SC (1435/4000) 32GB Corsair Vengeance DDR3/2400 
Hard DriveHard DriveCoolingOS
Samsung 850 Evo 1TB Samsung 850 Pro 512GB Noctua NH-U14S Windows 8.1 Pro 
MonitorKeyboardPowerCase
Dell P2415Q 24" 4K Display Corsair K90 RGB (MX Brown) SeaSonic M12II 850W SilverStone FT02S-W 
MouseMouse PadAudioAudio
eVGA Torq X10 Carbon eVGA Torq X10 Pad JBL Studio 530 Dayton SUB-120 12" Subwoofer 
CPUMotherboardRAMHard Drive
Intel Xeon D-1521 Supermicro X10SDV-4C-TLN2F 64GB Corsair Vengeance DDR4/2133 Samsung 850 Evo 500GB 
Hard DriveCoolingOSPower
Samsung 850 Evo 1TB bequiet! Silent Wings 2 120mm Windows Server 2016 Datacenter Corsair SF450 
Case
Fractal Design Node 202 
  hide details  
Reply
Deimos (G4.P)
(18 items)
 
 
Arcturus (G4.S)
(9 items)
 
CPUMotherboardGraphicsRAM
Intel i7 5930K ASUS X99 Deluxe II eVGA Titan X SC 64GB Corsair Vengeance DDR4/2800 
Hard DriveHard DriveHard DriveCooling
Intel 750 400GB Samsung 850 Pro 512GB Samsung 850 Evo 1TB HEATKILLER IV PRO CPU Block 
CoolingOSMonitorKeyboard
HEATKILLER IV XL GPU Block Windows 8.1 Pro Dell P2715Q Corsair K95 RGB 
PowerCaseMouseAudio
Corsair AX860i Silverstone Fortress 2 Silver eVGA TORQ X10 Carbon Denon AVR-S510BT 
AudioAudio
JBL Studio 530 Dayton SUB-120 
CPUMotherboardGraphicsRAM
Intel i5 4670k @ 4.0 Ghz ASUS Z87-PRO eVGA Titan X SC (1435/4000) 32GB Corsair Vengeance DDR3/2400 
Hard DriveHard DriveCoolingOS
Samsung 850 Evo 1TB Samsung 850 Pro 512GB Noctua NH-U14S Windows 8.1 Pro 
MonitorKeyboardPowerCase
Dell P2415Q 24" 4K Display Corsair K90 RGB (MX Brown) SeaSonic M12II 850W SilverStone FT02S-W 
MouseMouse PadAudioAudio
eVGA Torq X10 Carbon eVGA Torq X10 Pad JBL Studio 530 Dayton SUB-120 12" Subwoofer 
CPUMotherboardRAMHard Drive
Intel Xeon D-1521 Supermicro X10SDV-4C-TLN2F 64GB Corsair Vengeance DDR4/2133 Samsung 850 Evo 500GB 
Hard DriveCoolingOSPower
Samsung 850 Evo 1TB bequiet! Silent Wings 2 120mm Windows Server 2016 Datacenter Corsair SF450 
Case
Fractal Design Node 202 
  hide details  
Reply
post #12 of 18
Quote:
Originally Posted by hajile View Post

No, the correct way would be to realize that the number is entered as a string which is then typecast to an integer (keyboards enter numbers as characters). If you simply accept the input as the string it is, you don't need string -> int -> string to get to a solution.

Where did the OP say his input was a string rather than an integer?
Quote:
Originally Posted by hajile View Post

@OP
Simply check that the input string is 3 characters (after stripping whitespace and newlines). Once this is done, check that each char is a number, if so convert it and assign it. The time saving here is quite large because converting to/from string and int is inefficient.

Using modulus for such a problem (where you already have a string) is incredibly inefficient. To convert a single decimal digit character to its integer equivalent, just AND it with 00001111 (the ASCII decimal chars are 00110000 - 00111001, so that AND replaces the leading 0011 with 0000 -- note: asking for a single char to be converted to an integer should do exactly this optimization). This takes ONE computer cycle. To take a modulus of 10 requires a real division operation which is 30+ computer cycles (integer division is the single most inefficient operation there is).

Seems like we're prematurely optimizing a bit, don't you think? The "real" atoi in glibc doesn't perform any of these optimizations, as far as I can tell. It's actually fairly straight forward (albeit very hard to find). The only real optimization I see is the assumption that all ASCII digit characters appear in order, and thus the use of
Code:
unsigned long int digval = *nptr - '0';
to convert a digit character to an integer representation.

https://github.com/lattera/glibc/blob/master/dlfcn/eval.c#L34
Cube
(9 items)
 
  
CPUMotherboardRAMHard Drive
i7-4930k EVGA X79 Dark Corsair Vengeance Pro Samsung 840 Pro 
CoolingMonitorPowerCase
Corsair H100i Viewsonic VP2770 EVGA SuperNova 1000P2 Corsair Air 540 
Mouse
Corsair M65 
  hide details  
Reply
Cube
(9 items)
 
  
CPUMotherboardRAMHard Drive
i7-4930k EVGA X79 Dark Corsair Vengeance Pro Samsung 840 Pro 
CoolingMonitorPowerCase
Corsair H100i Viewsonic VP2770 EVGA SuperNova 1000P2 Corsair Air 540 
Mouse
Corsair M65 
  hide details  
Reply
post #13 of 18
Yet another solution would be to use stringstream:
Code:
int num = 123;

std::stringstream sstream;
sstream << num;

std::cout << "Digit 1: " << sstream.str().at(0) << "\n"
                << "Digit 2: " << sstream.str().at(1) << "\n"
                << "Digit 3: " << sstream.str().at(2) << std::endl;

Edited by poroboszcz - 10/28/13 at 6:30pm
buka
(17 items)
 
  
Reply
buka
(17 items)
 
  
Reply
post #14 of 18
Quote:
Originally Posted by hajile View Post

No, the correct way would be to realize that the number is entered as a string which is then typecast to an integer (keyboards enter numbers as characters). If you simply accept the input as the string it is, you don't need string -> int -> string to get to a solution.

@OP
Simply check that the input string is 3 characters (after stripping whitespace and newlines). Once this is done, check that each char is a number, if so convert it and assign it. The time saving here is quite large because converting to/from string and int is inefficient.

Using modulus for such a problem (where you already have a string) is incredibly inefficient. To convert a single decimal digit character to its integer equivalent, just AND it with 00001111 (the ASCII decimal chars are 00110000 - 00111001, so that AND replaces the leading 0011 with 0000 -- note: asking for a single char to be converted to an integer should do exactly this optimization). This takes ONE computer cycle. To take a modulus of 10 requires a real division operation which is 30+ computer cycles (integer division is the single most inefficient operation there is).
That assumes the number is entered though an interface....
Once again...
(13 items)
 
  
CPUMotherboardGraphicsRAM
i7 920 [4.28GHz, HT] Asus P6T + Broadcom NetXtreme II VisionTek HD5850 [900/1200] + Galaxy GT240 2x4GB G.Skill Ripjaw X [1632 MHz] 
Hard DriveOSMonitorKeyboard
Intel X25-M 160GB + 3xRAID0 500GB 7200.12 Window 7 Pro 64 Acer H243H + Samsung 226BW XARMOR-U9BL  
PowerCaseMouseMouse Pad
Antec Truepower New 750W Li Lian PC-V2100 [10x120mm fans] Logitech G9 X-Trac Pro 
  hide details  
Reply
Once again...
(13 items)
 
  
CPUMotherboardGraphicsRAM
i7 920 [4.28GHz, HT] Asus P6T + Broadcom NetXtreme II VisionTek HD5850 [900/1200] + Galaxy GT240 2x4GB G.Skill Ripjaw X [1632 MHz] 
Hard DriveOSMonitorKeyboard
Intel X25-M 160GB + 3xRAID0 500GB 7200.12 Window 7 Pro 64 Acer H243H + Samsung 226BW XARMOR-U9BL  
PowerCaseMouseMouse Pad
Antec Truepower New 750W Li Lian PC-V2100 [10x120mm fans] Logitech G9 X-Trac Pro 
  hide details  
Reply
post #15 of 18
Quote:
Originally Posted by jvolkman View Post

Where did the OP say his input was a string rather than an integer?
Seems like we're prematurely optimizing a bit, don't you think? The "real" atoi in glibc doesn't perform any of these optimizations, as far as I can tell. It's actually fairly straight forward (albeit very hard to find). The only real optimization I see is the assumption that all ASCII digit characters appear in order, and thus the use of
Code:
unsigned long int digval = *nptr - '0';
to convert a digit character to an integer representation.

https://github.com/lattera/glibc/blob/master/dlfcn/eval.c#L34
Nowhere did the OP state that the number was originally a string, but this type of operation is (in my experience) operating on some form of input which is most often transmitted in char form. If that assumption is correct, then my advice is correct. If not, then another approach may be in order.

As to the code you show. In short, the optimization you show is almost identical to what I describe (more below).
'0' === 00110000

let's take '5' (which is 00110101 in binary)

using the method above:
00110101 - 00110000 = 00000101

using the logical AND method:
00110101 & 00001111 = 00000101

The difference is that the unsigned subtraction method may not be as efficient in some implementation and (perhaps more importantly) can overflow the unsigned integer unless the input is first checked. For example, if the input were linefeed (00001101), subtracting 00110000 would cause an error due to there being no negative numbers (some processors may set an error flag while others might not). If we instead AND the numbers, we get the improper value of 13, but the program doesn't have the crash potential. The solution to both errors is to add a dozen instructions to check if the input is between 00110000 - 00111001 and signal a type conversion error if it is not.

As to premature optimization. That is decried by programmers every time a better solution is shown. If it's obvious, easy to implement, and doesn't stand in the way of future use cases then it's not premature and excluding it only means that you must look over your code later and refactor. Part of being a good programmer is recognizing these things and responding accordingly. Premature optimization would be something along the lines adjusting the algorithm to avoid conversion to decimal and working the whole thing in binary (though I don't see that working at all in this case, I think the point stands).

"LISP programmers know the value of everything and the cost of nothing." Unfortunately, most programmers have become this way with every language (and surprisingly, it's far less true of lisp programmers today because their skills are generally well above average). I can't tell you how many programmers don't realize how inefficient division is (perhaps because they've never designed a CPU like some of us have). They simply hope that the compiler does the right thing for them, but they usually have no idea if it can (and in most cases of division it can't).
post #16 of 18
Quote:
Originally Posted by hajile View Post

Nowhere did the OP state that the number was originally a string, but this type of operation is (in my experience) operating on some form of input which is most often transmitted in char form. If that assumption is correct, then my advice is correct. If not, then another approach may be in order.

Unless, of course, the point of the exercise is to split an integer value into its corresponding base 10 digits, thus learning various arithmetic operations and math routines provided by the language. That was the point I assumed.
Quote:
Originally Posted by hajile View Post

As to the code you show. In short, the optimization you show is almost identical to what I describe (more below).
'0' === 00110000

let's take '5' (which is 00110101 in binary)

using the method above:
00110101 - 00110000 = 00000101

using the logical AND method:
00110101 & 00001111 = 00000101

The difference is that the unsigned subtraction method may not be as efficient in some implementation and (perhaps more importantly) can overflow the unsigned integer unless the input is first checked. For example, if the input were linefeed (00001101), subtracting 00110000 would cause an error due to there being no negative numbers (some processors may set an error flag while others might not). If we instead AND the numbers, we get the improper value of 13, but the program doesn't have the crash potential. The solution to both errors is to add a dozen instructions to check if the input is between 00110000 - 00111001 and signal a type conversion error if it is not.

I think the only practical benefit to the AND method is potentially execution speed (if measurable) at the cost of being a slightly less obvious implementation. It still requires bounds checking to prevent 'wxy' from being interpreted as 789, so I don't really buy the overflow argument. But it's interesting nonetheless.
Quote:
Originally Posted by hajile View Post

As to premature optimization. That is decried by programmers every time a better solution is shown. If it's obvious, easy to implement, and doesn't stand in the way of future use cases then it's not premature and excluding it only means that you must look over your code later and refactor. Part of being a good programmer is recognizing these things and responding accordingly. Premature optimization would be something along the lines adjusting the algorithm to avoid conversion to decimal and working the whole thing in binary (though I don't see that working at all in this case, I think the point stands).

I think premature optimization in this case is suggesting that the OP use bitwise operations and avoid integer division in what is quite likely a simple programming exercise. Shaving nanoseconds off the execution time doesn't matter if the input is being read from the user via stdin (and needlessly converted from a string to an integer prior to the integer digit split operation, much to your chagrin smile.gif).
Quote:
Originally Posted by hajile View Post

"LISP programmers know the value of everything and the cost of nothing." Unfortunately, most programmers have become this way with every language (and surprisingly, it's far less true of lisp programmers today because their skills are generally well above average). I can't tell you how many programmers don't realize how inefficient division is (perhaps because they've never designed a CPU like some of us have). They simply hope that the compiler does the right thing for them, but they usually have no idea if it can (and in most cases of division it can't).

I'd spin it the other way, personally. Today's incredibly fast and cheap hardware lets programmers worry about things other than the efficiency of a division instruction on their platform. Most programmers target interpreted and JIT-compiled languages anyway [1], distancing themselves from such platform-specific optimizations and concerns.

[1] http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html
Cube
(9 items)
 
  
CPUMotherboardRAMHard Drive
i7-4930k EVGA X79 Dark Corsair Vengeance Pro Samsung 840 Pro 
CoolingMonitorPowerCase
Corsair H100i Viewsonic VP2770 EVGA SuperNova 1000P2 Corsair Air 540 
Mouse
Corsair M65 
  hide details  
Reply
Cube
(9 items)
 
  
CPUMotherboardRAMHard Drive
i7-4930k EVGA X79 Dark Corsair Vengeance Pro Samsung 840 Pro 
CoolingMonitorPowerCase
Corsair H100i Viewsonic VP2770 EVGA SuperNova 1000P2 Corsair Air 540 
Mouse
Corsair M65 
  hide details  
Reply
post #17 of 18
Quote:
Originally Posted by jvolkman View Post

Unless, of course, the point of the exercise is to split an integer value into its corresponding base 10 digits, thus learning various arithmetic operations and math routines provided by the language. That was the point I assumed.
I think the only practical benefit to the AND method is potentially execution speed (if measurable) at the cost of being a slightly less obvious implementation. It still requires bounds checking to prevent 'wxy' from being interpreted as 789, so I don't really buy the overflow argument. But it's interesting nonetheless.
I think premature optimization in this case is suggesting that the OP use bitwise operations and avoid integer division in what is quite likely a simple programming exercise. Shaving nanoseconds off the execution time doesn't matter if the input is being read from the user via stdin (and needlessly converted from a string to an integer prior to the integer digit split operation, much to your chagrin smile.gif).
I'd spin it the other way, personally. Today's incredibly fast and cheap hardware lets programmers worry about things other than the efficiency of a division instruction on their platform. Most programmers target interpreted and JIT-compiled languages anyway [1], distancing themselves from such platform-specific optimizations and concerns.

[1] http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html
Most of these exercises in "split a number" take that number from a command line (argv or prompt) both of which are string inputs. In day to day work, the idea of needing the individual digits of a number is typically limited to where the number should actually be treated as a string anyway. Conversion from decimal to string is very computationally expensive (write a low-level algorithm and you'll see). Eliminating these rounds of code is non-trivial and understanding this problem is part of becoming a good programmer (it is also quite impossible to recognize and correct this problem if it isn't mentioned by anyone).

I've done some asm for limited embedded systems where you don't have the room for that check (though I specifically mentioned that it is required in both cases if complete type safety is desired). The idea of the AND is similar to the idea of NaN. Sure it's output can be toxic, but it's not lethal (a little unlike NaN which is always toxic though not lethal to execution). The subtraction REQUIRES that an overflow bit be checked. If it's left in the set position, it will screw up an operation later.

Avoiding division is NEVER premature optimization IMHO. It's simply that detrimental to performance. Like I said in a previous post, almost every operation resolves in one clock cycle (assuming a 5 stage pipeline). For basic integer operations:
add, sub, or, and, neg, xor, cmp, shift, jump, move, load, store, etc are all handled in 1 clock cycle (load takes longer if a cache miss occurs)
mul usually takes 3-5 cycles
div takes 30+ cycles
these numbers are UNIVERSAL (that is, these are as fast as is currently known and only get slower from here).

No compiler can solve this fundamental hardware problem. Some compilers with the luxury of time may optimize for specific numbers (most optimize division by 2, 4, and 8 as shifts), but once you hit the real division unit, you're simply hoping the CPU has something it can run out of order otherwise your pipeline flushes and waits for that operation to complete. Since this entire problem starts to disappear when you eliminate or reduce divisions, there's no good reason not to consider your problem more carefully.

Programmers of today should worry about efficiency more than any programmer since the early 80s. Ten years ago, saying "don't optimize, just wait for the next generation of processors from Intel" was standard practice at most companies because that new generation would offer much better performance. Today, we have reached the point where doubling the silicon doesn't double the performance (in fact, it often barely nets 10-30% increase) and many people are still choosing to use older systems because a core2 is barely 2x slower than our cutting edge processors today (6-7 years later). Multi-core (seen as the answer to scaling CPU power) is much harder to accomplish and seems nearly impossible for some problem sets. Mobile compounds this problem by running processors that have performance comparable to chips from around 2004 (pentium4 and slower Athlon64). The idea that "the compiler can handle it" has been specifically disproven. If it were true, then the EPIC architecture (Itanium) and VLIW5/4 (older AMD GPUs) would be the only architectures in existence. Instead, it turns out that the idea to "build a better compiler" isn't the task it seemed and compilers are still incredibly stupid. While I would never recommend such an optimization for a language such as JS (it's 'supposed to' use 64-bit floats, but fast implementations actually use other implementations behind the scenes), the language in question is C++ (also note that using AND isn't platform specific -- all integer processors I know of have that fundamental operation).
post #18 of 18
Quote:
Originally Posted by hajile View Post

No, the correct way would be to realize that the number is entered as a string which is then typecast to an integer (keyboards enter numbers as characters). If you simply accept the input as the string it is, you don't need string -> int -> string to get to a solution.

@OP
Simply check that the input string is 3 characters (after stripping whitespace and newlines). Once this is done, check that each char is a number, if so convert it and assign it. The time saving here is quite large because converting to/from string and int is inefficient.

Using modulus for such a problem (where you already have a string) is incredibly inefficient. To convert a single decimal digit character to its integer equivalent, just AND it with 00001111 (the ASCII decimal chars are 00110000 - 00111001, so that AND replaces the leading 0011 with 0000 -- note: asking for a single char to be converted to an integer should do exactly this optimization). This takes ONE computer cycle. To take a modulus of 10 requires a real division operation which is 30+ computer cycles (integer division is the single most inefficient operation there is).
Who cares about efficiency in this problem? Are you programming for a computer with 400 words of memory and a 1 MHz CPU?
Akiyama Mio
(13 items)
 
  
CPUMotherboardGraphicsRAM
E6420 @ stock, 0.98v Asus P5N-E SLI Gainward GTX 460 1GB @ 800/1600/1900 2x2GB Kingston @ 800MHz 5-5-5-15 2T 
Hard DriveOptical DriveOSMonitor
WD 250GB, 320GB SATA/3, 16MB Cache, Seagate 1TB LG GSA-H62N 18x SATA Ubuntu 9.10 x86 & Win7 x86 Asus VW222U 
KeyboardPowerCase
Logitech Classic Corsair 650HX NZXT Apollo Black 
  hide details  
Reply
Akiyama Mio
(13 items)
 
  
CPUMotherboardGraphicsRAM
E6420 @ stock, 0.98v Asus P5N-E SLI Gainward GTX 460 1GB @ 800/1600/1900 2x2GB Kingston @ 800MHz 5-5-5-15 2T 
Hard DriveOptical DriveOSMonitor
WD 250GB, 320GB SATA/3, 16MB Cache, Seagate 1TB LG GSA-H62N 18x SATA Ubuntu 9.10 x86 & Win7 x86 Asus VW222U 
KeyboardPowerCase
Logitech Classic Corsair 650HX NZXT Apollo Black 
  hide details  
Reply
New Posts  All Forums:Forum Nav:
  Return Home
  Back to Forum: Coding and Programming
Overclock.net › Forums › Software, Programming and Coding › Coding and Programming › How would I separate a 3 digit number in C++?