Related
How to get an integer's sign and store it in a char? One way is:
int n = -5
char c;
if(n<0)
c = '-';
else
c = '+';
Or:
char c = n < 0 ? '-' : '+';
But is there a way to do it without conditionals?
There's the most efficient and portable way, but it doesn't win any beauty awards.
We can assume that the MSB of a signed integer is always set if it is negative. This is a 100% portable assumption even when taking exotic signedness formats in account (one's complement, signed magnitude). Therefore the fastest way is to simply mask out the MSB from the integer.
The MSB of any integer is found at location CHAR_BIT * sizeof(n) - 1;. On a typical 32 bit mainstream system, this would for example be 8 * 4 - 1 = 31.
So we can write a function like this:
_Bool is_signed (int n)
{
const unsigned int sign_bit_n = CHAR_BIT * sizeof(n) - 1;
return (_Bool) ((unsigned int)n >> sign_bit_n);
}
On x86-64 gcc 9.1 (-O3), this results in very efficient code:
is_signed:
mov eax, edi
shr eax, 31
ret
The advantage of this method is also that, unlike code such as x < 0, it won't risk getting translated into "branch if negative" instructions when ported.
Complete example:
#include <limits.h>
#include <stdio.h>
_Bool is_signed (int n)
{
const unsigned int sign_bit_n = CHAR_BIT * sizeof(n) - 1;
return (_Bool) ((unsigned int)n >> sign_bit_n);
}
int main (void)
{
int n = -1;
const char SIGNS[] = {' ', '-'};
char sign = SIGNS[is_signed(n)];
putchar(sign);
}
Disassembly (x86-64 gcc 9.1 (-O3)):
is_signed:
mov eax, edi
shr eax, 31
ret
main:
sub rsp, 8
mov rsi, QWORD PTR stdout[rip]
mov edi, 45
call _IO_putc
xor eax, eax
add rsp, 8
ret
This creates branchless code with gcc/clang on x86-64:
void storeneg(int X, char *C)
{
*C='+';
*C += (X<0)*('-'-'+');
}
https://gcc.godbolt.org/z/yua1go
char c = 43 + signbit(n) * 2 ;
char 43 is '+'
char 45 is '-'
signbit(NEGATIVE INTEGER) is true, converted to 1
int signbit(int) is included in cmath in C++ and math.h in C
I want to scan in a date in the form of mm/dd, so I've written this code:
#include <stdio.h>
int main (void)
{
int start_date[4];
scanf("%d%d/%d%d", &start_date[0], &start_date[1], &start_date[2], &start_date[3]);
printf("%d%d%d%d\n", start_date[0], start_date[1], start_date[2], start_date[3]);
return 0;
}
But when I enter the following for example:
04/20
scanf() reads this
4-419644000
How do I make it so that when I print out each element in start_date, I get this:
0420
when I enter the input from earlier?
Reading one digit at a time
Use %1d:
int n = scanf("%1d%1d/%1d%1d", &start_date[0], &start_date[1], &start_date[2], &start_date[3]);
if (n != 4) { …handle error… }
Note that this will accept both:
19/96
and
1 9/
9
6
as valid inputs. If you need the digits to be contiguous, you have to work harder. In general, it is usually best to read a line with fgets() (or POSIX's
getline()) and then parse the line with sscanf(). You can also consider checking the length of the string, etc.
What went wrong?
Incidentally, you said:
But when I enter the following for example:
04/20
scanf() reads this
4-419644000
What happens here is that the 04 is read by the first %d; the second %d fails because / doesn't match a number, so nothing is written to &start_date[1] (or the other two items), and scanf() returns 1. Since you didn't check the return value, you weren't aware of the problem. Note that the check should be as I showed (n != 4 where 4 is the number of items you expect to be converted). Checking for EOF would not work correctly; there wasn't an EOF on the file, but there was a conversion failure. Since you printed an uninitialized variable, the value you got was indeterminate ('undefined behaviour' in the jargon); a largish negative number is reasonable (as is any other value whatsoever, or a crash, or …). In fact, you have three indeterminate numbers smushed together, of which only the first is negative. Avoid undefined behaviour; always check that your input operations succeed — and don't use the results if they fail. (Or, at least, be very cautious about using the results if they fail; you need to be sure you know what's going on.)
The %d would consume the string "04", if you want to input digit by digit really, try %c, then adjust them to digit:
char start_data[4];
scanf("%c%c/%c%c", &start_date[0], &start_date[1], &start_date[2], &start_date[3]);
start_data[0] -= '0';
start_data[1] -= '0';
start_data[2] -= '0';
start_data[3] -= '0';
Another way, you can just input mm and dd and do arithmetic on it:
int mm, dd;
scanf("%d/%d", &mm, &dd);
int m0 = mm % 10;
int m1 = mm / 10;
int d0 = dd % 10;
int d1 = dd / 10;
Change the data type to char[], so your code look like this
#include <stdio.h>
int main (void)
{
char start_date[4];
scanf("%c%c/%c%c", &start_date[0], &start_date[1], &start_date[2], &start_date[3]);
printf("%c%c%c%c\n", start_date[0], start_date[1], start_date[2], start_date[3]);
return 0;
}
If you want to change the data type of each characters to integers you can change by look into the ASCII code then substract the characters with ASCII '0'
I think you should use strptime() instead. It's purpose-built for parsing standard date formats such as yours. Just read the entire "word" as a string and feed it to strptime().
This was too long for a comment, but you can see why this is happening here:
0x080484a7 <+58>: call 0x8048360 <__isoc99_scanf#plt>
0x080484ac <+63>: mov 0x2c(%esp),%ebx
0x080484b0 <+67>: mov 0x28(%esp),%ecx
0x080484b4 <+71>: mov 0x24(%esp),%edx
0x080484b8 <+75>: mov 0x20(%esp),%eax
0x080484bc <+79>: mov %ebx,0x10(%esp)
...
End of assembler dump.
(gdb) break *main+79
Breakpoint 4 at 0x80484bc
(gdb) r
Starting program: /root/test/testcode
04/21
Breakpoint 4, 0x080484bc in main ()
(gdb) i r
eax 0x4 4
ecx 0x80484fb 134513915
edx 0xb7fff000 -1207963648
ebx 0xb7fcc000 -1208172544
esp 0xbffff720 0xbffff720
ebp 0xbffff758 0xbffff758
esi 0x0 0
edi 0x0 0
eip 0x80484bc 0x80484bc <main+79>
eflags 0x286 [ PF SF IF ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) c
Continuing.
4-1207963648134513915-1208172544
Here's whats happening:
mov 0x2c(%esp),%ebx
mov 0x28(%esp),%ecx
mov 0x24(%esp),%edx
mov 0x20(%esp),%eax
These four mov statements are preparation for the printf() call. Each %d corresponds to one of the registers: eax ebx ecx edx
You can see that it is moving four bytes into each register. This is the reason you see gibberish. Each %d getting printed is expecting a 4-byte integer.
I set a breakpoint after all four of those mov statements, so lets look at what they contain:
eax 0x4 4
ecx 0x80484fb 134513915
edx 0xb7fff000 -1207963648
ebx 0xb7fcc000 -1208172544
This doesn't look right at all, but it does indeed correspond to what's on the stack:
0xbffff740: 0x00000004 0xb7fff000 0x080484fb 0xb7fcc000
These are the four values that wind up in the registers.
The first one is actually your 04 combined. It interpreted 04 as being within the bounds of %d, which is a 4-byte integer on my machine.
Since you tried to grab four %d's, the program continues as it should and prints out four %ds. In other words, it prints out four 4-byte integers.
The reason this is happening is what Jonathan Leffler explained: scanf is gobbling up the 04 into the first %d, then breaking on the /
You still have a printf() of %d%d%d%d though, so the program dutifully prints out the remaining 4-byte decimal values. Since scanf failed, the remaining 3 %ds contain whatever happened to be on the stack.
Unless you have another reason for using an array to store the individual digits, I suggest you just store the month and day as variables.
Also, because you know that there is a separator, accomodate it in your code. It is simpler.
This is the code you are looking for.
#include <stdio.h>
int main (void)
{
int month, day;
char sep;
scanf("%d%c%d", &month, &sep, &day);
printf("%d of %d\n", day, month);
return 0;
}
Explanation for the printing (Printing leading 0's in C):
The 0 indicates what you are padding with and the 5 shows the width of the integer number.
Example 1: If you use "%02d" (useful for dates) this would only pad zeros for numbers in the ones column. E.g., 06 instead of 6.
Example 2: "%03d" would pad 2 zeros for one number in the ones column and pad 1 zero for a number in the tens column. E.g., number 7 padded to 007 and number 17 padded to 017.
You could have also taken the data in as a string using %5s and further extract that data from the array of characters (string). Here is a good resource with examples. -> https://cplusplus.com/reference/cstdio/scanf/
I do feel that for your solution it would still have been an overkill, so I beleive the example code provided above is sufficient.
The standard div() function returns a div_t struct as parameter, for example:
/* div example */
#include <stdio.h> /* printf */
#include <stdlib.h> /* div, div_t */
int main ()
{
div_t divresult;
divresult = div (38,5);
printf ("38 div 5 => %d, remainder %d.\n", divresult.quot, divresult.rem);
return 0;
}
My case is a bit different; I have this
#define NUM_ELTS 21433
int main ()
{
unsigned int quotients[NUM_ELTS];
unsigned int remainders[NUM_ELTS];
int i;
for(i=0;i<NUM_ELTS;i++) {
divide_single_instruction("ient[i],&reminder[i]);
}
}
I know that the assembly language for division does everything in single instruction, so I need to do the same here to save on cpu cycles, which is bassicaly move the quotient from EAX and reminder from EDX into a memory locations where my arrays are stored. How can this be done without including the asm {} or SSE intrinsics in my C code ? It has to be portable.
Since you're writing to the arrays in-place (replacing numerator and denominator with quotient and remainder) you should store the results to temporary variables before writing to the arrays.
void foo (unsigned *num, unsigned *den, int n) {
int i;
for(i=0;i<n;i++) {
unsigned q = num[i]/den[i], r = num[i]%den[i];
num[i] = q, den[i] = r;
}
}
produces this main loop assembly
.L5:
movl (%rdi,%rcx,4), %eax
xorl %edx, %edx
divl (%rsi,%rcx,4)
movl %eax, (%rdi,%rcx,4)
movl %edx, (%rsi,%rcx,4)
addq $1, %rcx
cmpl %ecx, %r8d
jg .L5
There are some more complicated cases where it helps to save the quotient and remainder when they are first used. For example in testing for primes by trial division you often see a loop like this
for (p = 3; p <= n/p; p += 2)
if (!(n % p)) return 0;
It turns out that GCC does not use the remainder from the first division and therefore it does the division instruction twice which is unnecessary. To fix this you can save the remainder when the first division is done like this:
for (p = 3, q=n/p, r=n%p; p <= q; p += 2, q = n/p, r=n%p)
if (!r) return 0;
This speeds up the result by a factor of two.
So in general GCC does a good job particularly if you save the quotient and remainder when they are first calculated.
The general rule here is to trust your compiler to do something fast. You can always disassemble the code and check that the compiler is doing something sane. It's important to realise that a good compiler knows a lot about the machine, often more than you or me.
Also let's assume you have a good reason for needing to "count cycles".
For your example code I agree that the x86 "idiv" instruction is the obvious choice. Let's see what my compiler (MS visual C 2013) will do if I just write out the most naive code I can
struct divresult {
int quot;
int rem;
};
struct divresult divrem(int num, int den)
{
return (struct divresult) { num / den, num % den };
}
int main()
{
struct divresult res = divrem(5, 2);
printf("%d, %d", res.quot, res.rem);
}
And the compiler gives us:
struct divresult res = divrem(5, 2);
printf("%d, %d", res.quot, res.rem);
01121000 push 1
01121002 push 2
01121004 push 1123018h
01121009 call dword ptr ds:[1122090h] ;;; this is printf()
Wow, I was outsmarted by the compiler. Visual C knows how division works so it just precalculated the result and inserted constants. It didn't even bother to include my function in the final code. We have to read in the integers from console to force it to actually do the calculation:
int main()
{
int num, den;
scanf("%d, %d", &num, &den);
struct divresult res = divrem(num, den);
printf("%d, %d", res.quot, res.rem);
}
Now we get:
struct divresult res = divrem(num, den);
01071023 mov eax,dword ptr [num]
01071026 cdq
01071027 idiv eax,dword ptr [den]
printf("%d, %d", res.quot, res.rem);
0107102A push edx
0107102B push eax
0107102C push 1073020h
01071031 call dword ptr ds:[1072090h] ;;; printf()
So you see, the compiler (or this compiler at least) already does what you want, or something even more clever.
From this we learn to trust the compiler and only second-guess it when we know it isn't doing a good enough job already.
As a homework assignment we are required to calculate the harmonic mean using an assembly program being driven by a C program.
We are using 64-bit linux machines and are required to use 64-bit floating point numbers.
I am new to Assembly. I apologize for any bad coding practices or if my code is just flat out wrong.
The problem with the code is the result returns only the last number entered in floating-point format. I do not know where the error occurs, although I believe it to lie in the addDen function.
As an example: If you were to enter the numbers 5, 6, 7, 8 the result would return 8.0000.
Here is my code for the assembly program:
;Assembly function that computs the harmonic mean
;of an array of 64-bit floating-point numbers.
;Retrieves input using a C program.
;
;Harmonic mean is defined as Sum(n/((1/x1) + (1/x2) + ... + (1/xn)))
;
; expects:
; RDI - address of array
; RSI - length of the array
; returns
; XMMO - the harmonic average of array's values
global harmonicMean
section .data
Zero dd 0.0
One dd 1.0
section .text
harmonicMean:
push rbp
mov rbp, rsp ;C prologue
movss xmm10, [Zero] ;Holds tally of denominator
cvtsi2ss xmm0, rsi ;Take length and put it into xmm0 register
.whileLoop:
cmp rsi, 0 ;Is the length of array 0?
je .endwhile
call addDen ;Compute a denominator value and add it to sum
add rdi, 4 ;Add size of float to address
dec rsi ;Decrease the length
jmp .whileLoop
.endwhile:
divss xmm0, xmm10
leave
ret
;Calculates a number in the denominator
addDen:
push rdi
movss xmm8, [One]
movss xmm9, [rdi]
divss xmm8, xmm9
addss xmm10, xmm8
pop rdi
ret
In order to recreate the logic error, i will also include my driver program:
/*
* Harmonic Mean Driver
* Tyler Weaver
* 03-12-2014
*/
#include<stdio.h>
#define ARRAYSIZE 4
double harmonicMean(double *, unsigned);
int main(int argc, char **argv) {
int i;
double ary[ARRAYSIZE];
double hm;
printf("Enter %d f.p. values: ", ARRAYSIZE);
for (i = 0; i < ARRAYSIZE; i++) {
scanf(" %lf", &ary[i]);
}
hm = harmonicMean(ary, ARRAYSIZE);
printf("asm: harmonic mean is %lf\n", hm);
return 0;
}
Any help will be much appreciated!
Yes there seems to be float vs double confusion. You pass in a double array, but pretty much all of the asm code expects floats: you use the ss instructions and you assume size 4 and you return a float too.
– Jester
There was an issue with floats and doubles! I really appreciate both of your responses. I was confused because the instructor had told us to use floats in our assembly program he had used doubles in an example driver. I spoke with the instructor and he had fixed his instructions. I thank you again! – Tyler Weaver
here is the algorithm, is a mix between C and pseudo code
My suggestion is to write this program in C.
Then have the compiler output the related asm language
then use that asm output as a guide in writing your own program
! ----------------------------------------------------------
! This program reads a series of input data values and
! computes their arithmetic, geometric and harmonic means.
! Since geometric mean requires taking n-th root, all input
! data item must be all positive (a special requirement of
! this program , although it is not absolutely necessary).
! If an input item is not positive, it should be ignored.
! Since some data items may be ignored, this program also
! checks to see if no data items remain!
! ----------------------------------------------------------
PROGRAM ComputingMeans
IMPLICIT NONE
REAL :: X
REAL :: Sum, Product, InverseSum
REAL :: Arithmetic, Geometric, Harmonic
INTEGER :: Count, TotalNumber, TotalValid
Sum = 0.0 ! for the sum
Product = 1.0 ! for the product
InverseSum = 0.0 ! for the sum of 1/x
TotalValid = 0 ! # of valid items
READ(*,*) TotalNumber ! read in # of items
DO Count = 1, TotalNumber ! for each item ...
READ(*,*) X ! read it in
WRITE(*,*) 'Input item ', Count, ' --> ', X
IF (X <= 0.0) THEN ! if it is non-positive
WRITE(*,*) 'Input <= 0. Ignored' ! ignore it
ELSE ! otherwise,
TotalValid = TotalValid + 1 ! count it in
Sum = Sum + X ! compute the sum,
Product = Product * X ! the product
InverseSum = InverseSum + 1.0/X ! and the sum of 1/x
END IF
END DO
IF (TotalValid > 0) THEN ! are there valid items?
Arithmetic = Sum / TotalValid ! yes, compute means
Geometric = Product**(1.0/TotalValid)
Harmonic = TotalValid / InverseSum
WRITE(*,*) 'No. of valid items --> ', TotalValid
WRITE(*,*) 'Arithmetic mean --> ', Arithmetic
WRITE(*,*) 'Geometric mean --> ', Geometric
WRITE(*,*) 'Harmonic mean --> ', Harmonic
ELSE ! no, display a message
WRITE(*,*) 'ERROR: none of the input is positive'
END IF
END PROGRAM ComputingMeans
I have to split a number into its digits in order to display it on an LCD. Right now I use the following method:
pos = 7;
do
{
LCD_Display(pos, val % 10);
val /= 10;
pos--;
} while (pos >= 0 && val);
The problem with this method is that division and modulo operations are extremely slow on an MSP430 microcontroller. Is there any alternative to this method, something that either does not involve division or that reduces the number of operations?
A note: I can't use any library functions, such as itoa. The libraries are big and the functions themselves are rather resource hungry (both in terms of number of cycles, and RAM usage).
You could do subtractions in a loop with predefined base 10 values.
My C is a bit rusty, but something like this:
int num[] = { 10000000,1000000,100000,10000,1000,100,10,1 };
for (pos = 0; pos < 8; pos++) {
int cnt = 0;
while (val >= num[pos]) {
cnt++;
val -= num[pos];
}
LCD_Display(pos, cnt);
}
Yes, there's another way, originally invented (at least AFAIK) by Terje Mathiesen. Instead of dividing by 10, you (sort of) multiply by the reciprocal. The trick, of course, is that in integers you can't represent the reciprocal directly. To make up for that, you work with scaled integers. If we had floating point, we could extract digits with something like:
input = 123
first digit = integer(10 * (fraction(input * .1))
second digit = integer(100 * (fraction(input * .01))
...and so on for as many digits as needed. To do this with integers, we basically just scale those by 232 (and round each up, since we'll use truncating math). In C, the algorithm looks like this:
#include <stdio.h>
// here are our scaled factors
static const unsigned long long factors[] = {
3435973837, // ceil((0.1 * 2**32)<<3)
2748779070, // ceil((0.01 * 2**32)<<6)
2199023256, // etc.
3518437209,
2814749768,
2251799814,
3602879702,
2882303762,
2305843010
};
static const char shifts[] = {
3, // the shift value used for each factor above
6,
9,
13,
16,
19,
23,
26,
29
};
int main() {
unsigned input = 13754;
for (int i=8; i!=-1; i--) {
unsigned long long inter = input * factors[i];
inter >>= shifts[i];
inter &= (unsigned)-1;
inter *= 10;
inter >>= 32;
printf("%u", inter);
}
return 0;
}
The operations in the loop will map directly to instructions on most 32-bit processors. Your typical multiply instruction will take 2 32-bit inputs, and produce a 64-bit result, which is exactly what we need here. It'll typically be quite a bit faster than a division instruction as well. In a typical case, some of the operations will (or at least with some care, can) disappear in assembly language. For example, where I've done the inter &= (unsigned)-1;, in assembly language you'll normally be able to just use the lower 32-bit register where the result was stored, and just ignore whatever holds the upper 32 bits. Likewise, the inter >>= 32; just means we use the value in the upper 32-bit register, and ignore the lower 32-bit register.
For example, in x86 assembly language, this comes out something like:
mov ebx, 9 ; maximum digits we can deal with.
mov esi, offset output_buffer
next_digit:
mov eax, input
mul factors[ebx*4]
mov cl, shifts[ebx]
shrd eax, edx, cl
mov edx, 10 ; overwrite edx => inter &= (unsigned)-1
mul edx
add dl, '0'
mov [esi], dl ; effectively shift right 32 bits by ignoring 32 LSBs in eax
inc esi
dec ebx
jnz next_digit
mov [esi], bl ; zero terminate the string
For the moment, I've cheated a tiny bit, and written the code assuming an extra item at the beginning of each table (factors and shifts). This isn't strictly necessary, but simplifies the code at the cost of wasting 8 bytes of data. It's pretty easy to do away with that too, but I haven't bothered for the moment.
In any case, doing away with the division makes this a fair amount faster on quite a few low- to mid-range processors that lack dedicated division hardware.
Another way is using double dabble. This is a way to convert binary to BCD with only additions and bit shifts so it's very appropriate for microcontrollers. After splitting to BCDs you can easily print out each number
I would use a temporary string, like:
char buffer[8];
itoa(yourValue, buffer, 10);
int pos;
for(pos=0; pos<8; ++pos)
LCD_Display(pos, buffer[pos]); /* maybe you'll need a cast here */
edit: since you can't use library's itoa, then I think your solution is already the best, providing you compile with max optimization turned on.
You may take a look at this: Most optimized way to calculate modulus in C
This is my attempt at a complete solution. Credit should go to Guffa for providing the general idea. This should work for 32bit integers, signed or otherwise and 0.
#include <stdlib.h>
#include <stdio.h>
#define MAX_WIDTH (10)
static unsigned int uiPosition[] = {
1u,
10u,
100u,
1000u,
10000u,
100000u,
1000000u,
10000000u,
100000000u,
1000000000u,
};
void uitostr(unsigned int uiSource, char* cTarget)
{
int i, c=0;
for( i=0; i!=MAX_WIDTH; ++i )
{
cTarget[i] = 0;
}
if( uiSource == 0 )
{
cTarget[0] = '0';
cTarget[1] = '\0';
return;
}
for( i=MAX_WIDTH -1; i>=0; --i )
{
while( uiSource >= uiPosition[i] )
{
cTarget[c] += 1;
uiSource -= uiPosition[i];
}
if( c != 0 || cTarget[c] != 0 )
{
cTarget[c] += 0x30;
c++;
}
}
cTarget[c] = '\0';
}
void itostr(int iSource, char* cTarget)
{
if( iSource < 0 )
{
cTarget[0] = '-';
uitostr((unsigned int)(iSource * -1), cTarget + 1);
}
else
{
uitostr((unsigned int)iSource, cTarget);
}
}
int main()
{
char szStr[MAX_WIDTH +1] = { 0 };
// signed integer
printf("Signed integer\n");
printf("int: %d\n", 100);
itostr(100, szStr);
printf("str: %s\n", szStr);
printf("int: %d\n", -1);
itostr(-1, szStr);
printf("str: %s\n", szStr);
printf("int: %d\n", 1000000000);
itostr(1000000000, szStr);
printf("str: %s\n", szStr);
printf("int: %d\n", 0);
itostr(0, szStr);
printf("str: %s\n", szStr);
return 0;
}