I am struggling with an error while debugging my application, I have been able to point out that the error seems to happen in the call to the function adc_gain_enum_to_real_gain(),however I don't see why it goes wrong, I suspect is related to passing/reading the pointer &adc_gain. Any hints?
Thanks in advance!
void saadc_handler_interrupt(nrf_drv_saadc_evt_t const * const p_event)
{
uint32_t err_code;
uint16_t voltage;
nrf_saadc_value_t adc_result;
uint16_t tmp_voltage;
float adc_gain;
if (p_event->type == NRF_DRV_SAADC_EVT_CALIBRATEDONE)
{
m_adc_cal_in_progress = false;
}
else if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
{
adc_result = p_event->data.done.p_buffer[0];
err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, 1);
APP_ERROR_CHECK(err_code);
err_code = adc_gain_enum_to_real_gain(ADC_GAIN, &adc_gain); //<===HERE!!
APP_ERROR_CHECK(err_code);
float tmp = adc_result / (( (1/6) / ADC_REFERENCE_VOLTAGE) * pow(2, ADC_RESOLUTION_BITS));
tmp_voltage = (uint16_t) ((tmp / m_battery_divider_factor) * 1000);
voltage = ( (tmp_voltage + 5) / 10) * 10; // Round the value.
NRF_LOG_INFO("Read value from saadc %d\nV",voltage);
batt_event_handler_adc(voltage);
}
//nrf_drv_saadc_uninit();
}
Such a function is
uint32_t adc_gain_enum_to_real_gain(nrf_saadc_gain_t gain_reg, float * const real_val)
{
switch(gain_reg)
{
case NRF_SAADC_GAIN1_6: *real_val = 1 / (float)6;
break;
case NRF_SAADC_GAIN1_5: *real_val = 1 / (float)5;
break;
case NRF_SAADC_GAIN1_4: *real_val = 1 / (float)4;
break;
case NRF_SAADC_GAIN1_3: *real_val = 1 / (float)3;
break;
case NRF_SAADC_GAIN1_2: *real_val = 1 / (float)2;
break;
case NRF_SAADC_GAIN1: *real_val = 1;
break;
case NRF_SAADC_GAIN2: *real_val = 2;
break;
case NRF_SAADC_GAIN4: *real_val = 3;
break;
default: return M_BATT_STATUS_CODE_INVALID_PARAM;
};
return M_BATT_STATUS_CODE_SUCCESS;
}
Here
float tmp = adc_result / (( (1/6) / ADC_REFERENCE_VOLTAGE) * pow(2, ADC_RESOLUTION_BITS));
(1/6) will always evaluate to 0. It's an integer division!
So the whole expression (( (1/6) / ADC_REFERENCE_VOLTAGE) * pow(2, ADC_RESOLUTION_BITS)) results in 0. (note: floating point here), which in turn provokes a division by zero here adc_result / ....
To fix this either do
(1./6)
or
(1/6.)
or
((float) 1/6)
or
(1 /(float) 6)
or any combination of the above.
Unrelated but another cause of trouble related to integer division as well is here:
(tmp_voltage + 5) / 10
Fix as above.
Related
i have an array of n length fullfilled by 16 bit (int16) pcm raw data,the data is in 44100 sample_rate
and stereo,so i have in my array first 2 bytes left channel then right channel etc...i tried to implement a simple low pass converting my array into floating points -1 1,the low pass works but there are round errors that cause little pops in the sound
now i do simply this :
INT32 left_id = 0;
INT32 right_id = 1;
DOUBLE filtered_l_db = 0.0;
DOUBLE filtered_r_db = 0.0;
DOUBLE last_filtered_left = 0;
DOUBLE last_filtered_right = 0;
DOUBLE l_db = 0.0;
DOUBLE r_db = 0.0;
DOUBLE low_filter = filter_freq(core->audio->low_pass_cut);
for(UINT32 a = 0; a < (buffer_size/2);++a)
{
l_db = ((DOUBLE)input_buffer[left_id]) / (DOUBLE)32768;
r_db = ((DOUBLE)input_buffer[right_id]) / (DOUBLE)32768;
///////////////LOW PASS
filtered_l_db = last_filtered_left +
(low_filter * (l_db -last_filtered_left ));
filtered_r_db = last_filtered_right +
(low_filter * (r_db - last_filtered_right));
last_filtered_left = filtered_l_db;
last_filtered_right = filtered_r_db;
INT16 l = (INT16)(filtered_l_db * (DOUBLE)32768);
INT16 r = (INT16)(filtered_r_db * (DOUBLE)32768);
output_buffer[left_id] = (output_buffer[left_id] + l);
output_buffer[right_id] = (output_buffer[right_id] + r);
left_id +=2;
right_id +=2;
}
PS: the input buffer is an int16 array with the pcm data from -32767 to 32767;
i found this function here
Low Pass filter in C
and was the only one that i could understand xd
DOUBLE filter_freq(DOUBLE cut_freq)
{
DOUBLE a = 1.0/(cut_freq * 2 * PI);
DOUBLE b = 1.0/SAMPLE_RATE;
return b/(a+b);
}
my aim is instead to have absolute precision on the wave,and to directly low pass using only integers
with the cost to lose resolution on the filter(and i'm ok with it)..i saw a lot of examples but i really didnt understand anything...someone of you would be so gentle to explain how this is done like you would explain to a little baby?(in code or pseudo code rapresentation) thank you
Assuming the result of function filter_freq can be written as a fraction m/n your filter calculation basically is
y_new = y_old + (m/n) * (x - y_old);
which can be transformed to
y_new = ((n * y_old) + m * (x - y_old)) / n;
The integer division / n truncates the result towards 0. If you want rounding instead of truncation you can implement it as
y_tmp = ((n * y_old) + m * (x - y_old));
if(y_tmp < 0) y_tmp -= (n / 2);
else y_tmp += (n / 2);
y_new = y_tmp / n
In order to avoid losing precision from dividing the result by n in one step and multiplying it by n in the next step you can save the value y_tmp before the division and use it in the next cycle.
y_tmp = (y_tmp + m * (x - y_old));
if(y_tmp < 0) y_new = y_tmp - (n / 2);
else y_new = y_tmp + (n / 2);
y_new /= n;
If your input data is int16_t I suggest to implement the calculation using int32_t to avoid overflows.
I tried to convert the filter in your code without checking other parts for possible problems.
INT32 left_id = 0;
INT32 right_id = 1;
int32_t filtered_l_out = 0; // output value after division
int32_t filtered_r_out = 0;
int32_t filtered_l_tmp = 0; // used to keep the output value before division
int32_t filtered_r_tmp = 0;
int32_t l_in = 0; // input value
int32_t r_in = 0;
DOUBLE low_filter = filter_freq(core->audio->low_pass_cut);
// define denominator and calculate numerator
// use power of 2 to allow bit-shift instead of division
const uint32_t filter_shift = 16U;
const int32_t filter_n = 1U << filter_shift;
int32_t filter_m = (int32_t)(low_filter * filter_n)
for(UINT32 a = 0; a < (buffer_size/2);++a)
{
l_in = input_buffer[left_id]);
r_in = input_buffer[right_id];
///////////////LOW PASS
filtered_l_tmp = filtered_l_tmp + filter_m * (l_in - filtered_l_out);
if(last_filtered_left < 0) {
filtered_l_out = last_filtered_left - filter_n/2;
} else {
filtered_l_out = last_filtered_left + filter_n/2;
}
//filtered_l_out /= filter_n;
filtered_l_out >>= filter_shift;
/* same calculation for right */
INT16 l = (INT16)(filtered_l_out);
INT16 r = (INT16)(filtered_r_out);
output_buffer[left_id] = (output_buffer[left_id] + l);
output_buffer[right_id] = (output_buffer[right_id] + r);
left_id +=2;
right_id +=2;
}
As your filter is initialized with 0 it may need several samples to follow a possible step to the first input value. Depending on your data it might be better to initialize the filter based on the first input value.
I've tried a few things, any it seems that at best I'm 1.5x slower than the printf() family of functions, which boggles my mind a bit. I think what I'm up against in this situation is the addressing of my device is 32bit, and I don't have an FPU. I've tried a couple of "ftoa()" implementations and constrained them to only look for 2 digits on the left of the decimal point, and left myself some breadcrumbs as to what the total length is of a larger overall string that I'm trying to build. At the end of the day, it seems like the nature of an array of 8-bit elements on a 32bit system is leading to a bunch of hidden shift operations, bitwise "OR" and bitwise NAND operations that are just slowing things down ridiculously...
Anyone have any general tips for this situation? (other than a re-architect to an 8.24 fixed point design) I've tried the compiler optimizations from wysiwyg to execution speed focused, nothing seems to beat snprintf.
Here's the fastest one that I had tried:
#if (__DEBUG)
#define DATA_FIFO_SIZE (8)
#else
#define DATA_FIFO_SIZE (1024)
#endif
typedef struct
{
int32_t rval[4];
double cval[4];
uint16_t idx;
uint16_t padding; //#attention the compiler was padding with 2 bytes to align to 32bit
} data_fifo_entry;
const char V_ERR_MSG[7] = "ERROR,\0";
static data_fifo_entry data_fifo[DATA_FIFO_SIZE];
static char embed_text[256];
/****
* float to ASCII, adapted from
* https://stackoverflow.com/questions/2302969/how-to-implement-char-ftoafloat-num-without-sprintf-library-function-i#7097567
*
****/
//#attention the following floating point #defs are linked!!
#define MAX_DIGITS_TO_PRINT_FLOAT (6)
#define MAX_SUPPORTED_PRINTABLE_FLOAT (+999999.99999999999999999999999999)
#define MIN_SUPPORTED_PRINTABLE_FLOAT (-999999.99999999999999999999999999)
#define FLOAT_TEST6 (100000.0)
#define FLOAT_TEST5 (10000.0)
#define FLOAT_TEST4 (1000.0)
#define FLOAT_TEST3 (100.0)
#define FLOAT_TEST2 (10.0)
#define FLOAT_TEST1 (1.0)
static inline int ftoa(char *s, const float f_in, const uint8_t precision)
{
float f_p = 0.0001;
float n = f_in;
int neg = (n < 0.0);
int length = 0;
switch (precision)
{
case (1):
{
f_p = 0.1;
break;
}
case (2):
{
f_p = 0.01;
break;
}
case (3):
{
f_p = 0.001;
break;
}
//case (4) is the default assumption
case (5):
{
f_p = 0.00001;
break;
}
case (6):
{
f_p = 0.000001;
break;
}
default: //already assumed, no assignments here
{
break;
}
} /* switch */
// handle special cases
if (isnan(n))
{
strcpy(s, "nan\0");
length = 4;
}
else if ((isinf(n)) || (n >= MAX_SUPPORTED_PRINTABLE_FLOAT) ||
((-1.0 * n) < MIN_SUPPORTED_PRINTABLE_FLOAT))
{
strcpy(s, "inf\0");
length = 4;
}
else if (n == 0.0)
{
int idx;
s[length++] = '+';
s[length++] = '0';
s[length++] = '.';
for (idx = 0; idx < precision; idx++)
{
s[length++] = '0';
}
s[length++] = '\0';
}
else if (((n > 0.0) && (n < f_p)) || ((n < 0.0) && ((-1.0 * n) < f_p)))
{
int idx;
if (n >= 0.0)
{
s[length++] = '+';
}
else
{
s[length++] = '-';
}
s[length++] = '0';
s[length++] = '.';
for (idx = 1; idx < precision; idx++)
{
s[length++] = '0';
}
s[length++] = '\0';
}
else
{
int digit, m;
if (neg)
{
n = -n;
}
// calculate magnitude
if (n >= FLOAT_TEST6)
{
m = 6;
}
else if (n >= FLOAT_TEST5)
{
m = 5;
}
else if (n >= FLOAT_TEST4)
{
m = 4;
}
else if (n >= FLOAT_TEST3)
{
m = 3;
}
else if (n >= FLOAT_TEST2)
{
m = 2;
}
else if (n >= FLOAT_TEST1)
{
m = 1;
}
else
{
m = 0;
}
if (neg)
{
s[length++] = '-';
}
else
{
s[length++] = '+';
}
// set up for scientific notation
if (m < 1.0)
{
m = 0;
}
// convert the number
while (n > f_p || m >= 0)
{
double weight = pow(10.0, m);
if ((weight > 0) && !isinf(weight))
{
digit = floor(n / weight);
n -= (digit * weight);
s[length++] = '0' + digit;
}
if ((m == 0) && (n > 0))
{
s[length++] = '.';
}
m--;
}
s[length++] = '\0';
}
return (length - 1);
} /* ftoa */
static inline void print2_and_idx(int8_t idx1, int8_t idx2, uint16_t fifo_idx)
{
//#attention 10 characters already in the buffer, idx does NOT start at zero
uint8_t idx = V_PREFIX_LENGTH;
char scratch[16] = {'\0'};
char * p_fifo_id;
if ((idx1 >= 0) && (idx1 < MAX_IDX) && (idx2 >= 0) && (idx2 < MAX_IDX) &&
(fifo_idx >= 0) && (fifo_idx < DATA_FIFO_SIZE))
{
ftoa(scratch, data_fifo[fifo_idx].cval[idx1], 4);
memcpy((void *)&embed_text[idx += 7], (void *)scratch, 7);
embed_text[idx++] = ',';
ftoa(scratch, data_fifo[fifo_idx].cval[idx2], 4);
memcpy((void *)&embed_text[idx += 7], (void *)scratch, 7);
embed_text[idx++] = ',';
//!\todo maybe print the .idx as fixed width, zero pad to 5 digits
p_fifo_id = utoa((char *)&embed_text[idx], (unsigned int)data_fifo[fifo_idx].idx, 10);
idx += strlen(p_fifo_id);
embed_text[idx++] = ',';
}
else
{
memcpy((void *)&embed_text[idx], (void *)V_ERR_MSG, 7);
}
} /* print2_and_idx */
Instead of using *printf() with FP arguments, convert the FP values first into scaled integers.
With still calling snprintf(), yet with integer and simple character arguments, my code was about 20x faster than the baseline.
Your mileage may vary. YMMV.
//baseline
void format2double_1(char *mystr, double pi, double e) {
snprintf(mystr, 22, "{%+0.4f,%+0.4f}", pi, e);
//puts(mystr);
}
void format2double_2(char *mystr, double pi, double e) {
int pi_i = (int) lrint(pi * 10000.0);
int api_i = abs(pi_i);
int e_i = (int) lrint(e * 10000.0);
int ae_i = abs(e_i);
snprintf(mystr, 22, "{%c%d.%04d,%c%d.%04d}", //
"+-"[pi_i < 0], api_i / 10000, api_i % 10000, //
"+-"[e_i < 0], ae_i / 10000, ae_i % 10000);
//puts(mystr);
}
[edit]
For a proper -0.0 text, use "+-"[!!signbit(pi)]
[edit]
Some idea for OP to consider as a ftoa() replacement. Central code is lrint(f_in * fscale[precision]); which rounds and scales. Untested.
#define PRINTABLE_MAGNITUDE_LIMIT 1000000
int ftoa_1(char *s, const float f_in, const uint8_t precision) {
int n;
sprintf(s, "%+.*f%n", precision, f_in, &n);
return n;
}
int ftoa_2(char *s, const float f_in, const uint8_t precision) {
float fscale[] = { 1, 10, 100, 1000, 10000, 100000, 1000000 };
long iscale[] = { 1, 10, 100, 1000, 10000, 100000, 1000000 };
assert(precision > 0 && precision < sizeof fscale / sizeof fscale[0]);
// gross range check
if (f_in > -PRINTABLE_MAGNITUDE_LIMIT && f_in < PRINTABLE_MAGNITUDE_LIMIT) {
long value = lrint(f_in * fscale[precision]);
value = labs(value);
long scale = iscale[precision];
long ipart = value / scale;
long fpart = value % scale;
// fine range check
if (ipart < PRINTABLE_MAGNITUDE_LIMIT) {
int n;
sprintf(s, "%c%ld:%0*ld%n", signbit(f_in) ? '-' : '+', ipart, precision,
fpart, &n);
return n;
}
}
// Out of range values need not be of performance concern for now.
return ftoa_1(s, f_in, precision);
}
[edit]
To convert a positive or 0 integer to a string quickly without the need to shift the buffer or reverse it, see below. It also returns the string length for subsequent string building.
// Convert an unsigned to a decimal string and return its length
size_t utoa_length(char *dest, unsigned u) {
size_t len = 0;
if (u >= 10) {
len = utoa_length(dest, u/10);
dest += len;
}
dest[0] = '0' + u%10;
dest[1] = '\0';
return len + 1;
}
In a similar vein of #chux's answer, if the remaining snprintf is still slow you can go down the rabbit hole of hand-composing strings/hand-rendering integers.
char *fmtp04f(char *buf, char *lim, double d) {
// if there's no space at all don't bother
if(buf==lim) return buf;
// 10 characters in maximum 32 bit integer, one for the dot,
// one for the terminating NUL in debug prints
char b[12];
// current position in the buffer
char *bp = b;
// scale and round
int32_t i = lrint(d * 10000.);
// write sign and fix i sign
// (we do have at least one character available in buf)
if(signbit(d)) {
*buf++='-';
i = -i;
} else {
*buf++='+';
}
// *always* write down the last 4 digits, even if they are zeroes
// (they'll become the 4 digits after the decimal dot)
for(; bp!=b+4; ) {
*bp++ = '0' + i%10;
i/=10;
}
*bp++='.';
// write down the remaining digits, writing at least one
do {
*bp++ = '0' + i%10;
i/=10;
} while(i != 0);
// bp is at the character after the last, step back
--bp;
// data is now into b *in reversed order*;
// reverse-copy it into the user-provided buffer
while(buf!=lim) {
*buf++ = *bp;
// check before decrementing, as a pointer to one-before-first
// is not allowed in C
if(bp == b) break;
--bp;
}
if(buf!=lim) *buf=0; // "regular" case: terminate *after*
else lim[-1]=0; // bad case: truncate
return buf;
}
void doformat(char *buf, char *lim, double a, double b) {
if(buf==lim) return; // cannot do anything
*buf++='{';
if(buf==lim) goto end;
buf = fmtp04f(buf, lim, a);
if(buf==lim) return; // already terminated by fmtp04f
*buf++=',';
if(buf==lim) goto end;
buf = fmtp04f(buf, lim, b);
if(buf==lim) return; // idem
*buf++='}';
if(buf==lim) goto end;
*buf++=0;
end:
lim[-1]=0; // always terminate
}
It passes some random tests, so I'm reasonably confident that it is not too wrong.
For some reason, #chux version on my machine (64 bit Linux, gcc 6.3) is generally 2/3 times faster than the baseline, while my version is usually 10/30 times faster than the baseline. I don't know if this is because my snprintf is particularly good or particularly bad. As said above, YMMV.
I am using code from the Waveshare website ( for use with the ADDA Waveshare board put on a RPi3 ) : http://www.waveshare.com/wiki/File:High-Precision-AD-DA-Board-Code.7z
*********************************************************************************************************
* name: main
* function:
* parameter: NULL
* The return value: NULL
*********************************************************************************************************
*/
int main()
{
uint8_t id;
int32_t adc[8];
int32_t volt[8];
uint8_t i;
uint8_t ch_num;
int32_t iTemp;
uint8_t buf[3];
if (!bcm2835_init())
return 1;
bcm2835_spi_begin();
bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_LSBFIRST ); // The default
bcm2835_spi_setDataMode(BCM2835_SPI_MODE1); // The default
bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_1024); // The default
bcm2835_gpio_fsel(SPICS, BCM2835_GPIO_FSEL_OUTP);//
bcm2835_gpio_write(SPICS, HIGH);
bcm2835_gpio_fsel(DRDY, BCM2835_GPIO_FSEL_INPT);
bcm2835_gpio_set_pud(DRDY, BCM2835_GPIO_PUD_UP);
//ADS1256_WriteReg(REG_MUX,0x01);
//ADS1256_WriteReg(REG_ADCON,0x20);
// ADS1256_CfgADC(ADS1256_GAIN_1, ADS1256_15SPS);
id = ADS1256_ReadChipID();
printf("\r\n");
printf("ID=\r\n");
if (id != 3)
{
printf("Error, ASD1256 Chip ID = 0x%d\r\n", (int)id);
}
else
{
printf("Ok, ASD1256 Chip ID = 0x%d\r\n", (int)id);
}
ADS1256_CfgADC(ADS1256_GAIN_1, ADS1256_15SPS);
ADS1256_StartScan(0);
ch_num = 8;
//if (ADS1256_Scan() == 0)
//{
//continue;
//}
while(1)
{
while((ADS1256_Scan() == 0));
for (i = 0; i < ch_num; i++)
{
adc[i] = ADS1256_GetAdc(i);
volt[i] = (adc[i] * 100) / 167;
}
for (i = 0; i < ch_num; i++)
{
buf[0] = ((uint32_t)adc[i] >> 16) & 0xFF;
buf[1] = ((uint32_t)adc[i] >> 8) & 0xFF;
buf[2] = ((uint32_t)adc[i] >> 0) & 0xFF;
printf("%d=%02X%02X%02X, %8ld", (int)i, (int)buf[0],
(int)buf[1], (int)buf[2], (long)adc[i]);
iTemp = volt[i]; /* uV */
if (iTemp < 0)
{
iTemp = -iTemp;
printf(" (-%ld.%03ld %03ld V) \r\n", iTemp /1000000, (iTemp%1000000)/1000, iTemp%1000);
}
else
{
printf(" ( %ld.%03ld %03ld V) \r\n", iTemp /1000000, (iTemp%1000000)/1000, iTemp%1000);
}
}
printf("\33[%dA", (int)ch_num);
bsp_DelayUS(100000);
}
bcm2835_spi_end();
bcm2835_close();
return 0;
}
Please help me figure out what this piece does in the main():
for (i = 0; i < ch_num; i++)
{
adc[i] = ADS1256_GetAdc(i);
volt[i] = (adc[i] * 100) / 167;
}
The constants (being 100 and 167) are not explained. What exactly are they trying to do in this 'calibration' and what do these constants depend upon?
Learning to read datasheets is an important skill for embedded programming.
The ADC on this chip returns a 24 bit signed value. The datasheet says
The ADS1255/6 full-scale input voltage equals ±2VREF/PGA.
Full-scale is 0x7FFFFF or 8388607.
I believe VRef is 2.5V, and the code sets PGA to 1 with ADS1256_CfgADC(ADS1256_GAIN_1, ADS1256_15SPS);
So an adc[i] value of 1 represents 1/0x7FFFFF of (2*2.5/1)Volts or 0.596 microvolts. We can convert the raw reading to microvolts by multiplying by 5000000 / 8388607. By multiplying by a number that large would overflow a 32 bit int, so let's reduce.
5000000 / 8388607 ~= 500/839 ~= 100/167.
(It would be possible to get a little more precision without overflow by multiplying by 250/419)
Looking specifically at this piece of code (which seems to be the actual question
for (i = 0; i < ch_num; i++)
{
adc[i] = ADS1256_GetAdc(i);
volt[i] = (adc[i] * 100) / 167;
}
It reads a number of ADC channels (0 through ch_num-1) and then does a crude conversion of each ADC value to a percentage of 167.
Consider the way we normally do percentage calculations as (a/b)*100. In other words, work out what fraction a is of b and then multiply by 100. But with integer math, the initial division will yield zero for all values < b, and the multiply won't affect that.
So we rewrite (a/b)*100 as (a*100)/b. Now the division occurs after the multiply and you will get non-zero results.
More specifically consider this example
(100/167) * 100 should become 0.59 * 100 = 59%. But with integer math you get (100/167) * 100 = (0) * 100 = 0%. After the rewrite you have (100*100)/167 = (10000)/167 = 59.
This is a standard trick with integer math.
i have to write a program that counts all vowels in a text & gives out the percentage of every vowel for the whole text.
For whatever reason we are not allowed to use arrays, but instead should do it with getchar().
#include <stdio.h>
#include <ctype.h>
int main() {
int current;
int cntAll = 0;
int cntA = 0, cntE = 0, cntI = 0, cntO = 0, cntU = 0;
int pA = 0, pE = 0, pI = 0, pO = 0, pU = 0;
printf("Enter Text: ");
while ((current = getchar()) != EOF){
if (isspace(current)) continue; // check for whitespace, if whitespace continue
else {
switch (current) { // check for vowel & increase vowelcount
case 'a':
cntA += 1;
case 'A':
cntA += 1;
case 'e':
cntE += 1;
case 'E':
cntE += 1;
case 'i':
cntI += 1;
case 'I':
cntI += 1;
case 'o':
cntO += 1;
case 'O':
cntO += 1;
case 'u':
cntU += 1;
case 'U':
cntU += 1;
}
}
cntAll++;
}
pA = (cntA / cntAll) * 100;
pE = (cntE / cntAll) * 100;
pI = (cntI / cntAll) * 100;
pO = (cntO / cntAll) * 100;
pU = (cntU / cntAll) * 100;
printf("\nLetters: %d\nPercentage A: %d\nPercentage E: %d\nPercentage I: %d\nPercentage O: %d\nPercentage U: %d\n",cntAll,pA,pE,pI,pO,pU);
system("PAUSE");
return 0;
}
Increasing the cntAll value works without problems, but it doesn't count the individual vowels for whatever reason.
Would appreciate any help!
Edited:
#include <stdio.h>
#include <ctype.h>
int main() {
int current;
int cntAll = 0;
int cntA = 0, cntE = 0, cntI = 0, cntO = 0, cntU = 0;
double pA = 0, pE = 0, pI = 0, pO = 0, pU = 0;
printf("Enter Text: ");
while ((current = getchar()) != EOF){
if (isspace(current)) continue;
else {
switch (current) {
case 'a':case 'A':
cntA += 1;
break;
case 'e':case 'E':
cntE += 1;
break;
case 'i':case 'I':
cntI += 1;
break;
case 'o':case 'O':
cntO += 1;
break;
case 'u':case 'U':
cntU += 1;
break;
}
}
cntAll++;
}
pA = 100.0 * cntA / cntAll;
pE = 100.0 * cntE / cntAll;
pI = 100.0 * cntI / cntAll;
pO = 100.0 * cntO / cntAll;
pU = 100.0 * cntU / cntAll;
printf("\nLetters: %d\nPercentage A: %.2lf\nPercentage E: %.2lf\nPercentage I: %.2lf\nPercentage O: %.2lf\nPercentage U: %.2lf\n",cntAll,pA,pE,pI,pO,pU);
system("PAUSE");
return 0;
}
cheers
You need to insert break statements between the cases.
Otherwise the program will execute all the statements below the one first entered. Actually this is a good feature. It allows you to consider multiple labels at the same time. Putting this together you get:
switch (current){
case 'a': case 'A':
cntA += 1;
break; // Don't follow through to the other cases.
case 'b': case 'B': /*etc*/
After this, note that (cntA / cntAll) * 100; will evaluate the expression in parentheses in integer arithmetic, which will truncate it to 0 in most cases. The fix is to write it as
100 * cntA / cntAll;
This will still truncate to an integer. If that's not tolerable then consider using the floating point expression 100.0 * cntA / cntAll and change your printf formatters accordingly. Using floating point is arguably better anyway as it obviates the potential for overflow when evaluating 100 * cntA.
case labels falls through to the next one below it without a break.
So if you read an 'a' then all the cases in your switch will be executed.
You need something like
switch (current) { // check for vowel & increase vowelcount
case 'a':
cntA += 1;
break; // <-- Note break here
...
First thing i notice is that you are missing break on every switch case. This will lead to wrong behaviour.
Second thing:
pA = (cntA / cntAll) * 100;
will calculate cntS/cntAll first which is <0. This value will be interpreted as integer so you always have 0*100 which is 0. You can rewrite it as
pA = (cntA * 100 ) / cntAll;
In that case you don't have to cast to float to get the right result. Note that for large cntA you may overflow.
i am working on a calculator project.
i am using a method to separate the char and numeric values.
but i am getting problem on when i have a decimal value, because result shown 0 when decimal value runs.
here is the code.
List<Double> numbers = new ArrayList<>();
List<Character> operators = new ArrayList<>();
..................
void testing() {
String userInput = "234+234+234";
/* ignore the line above its just for understanding */
/*the above works fine but if we change it to below its dont work.*/
String userInput = "234+2.3+4.2";
/* The both lines above are just for understanding actually i am getting text from edittext*/
String userInput = currentcalc.getText().toString();
for (char c : userInput.toCharArray()) {
if (!Character.isDigit(c)) {
s1 = Double.parseDouble(s2);
numbers.add(s1);
operators.add(c);
handler++;
s2 = "";
s1 = 0;
} else {
s = Character.toString(c);
s2 += s;
}
}
result();
}
result = 0.0
s and s2 are strings and s1 is double. and in my code if c is not a digit it is saving value of operator like +,- etc and else it is saving value of digits and other things. i want to know that why "." is not being save via this code and why result is showing 0.0
the result(); code is here below
void result() {
double total4 = 0;
s1 = Double.parseDouble(s2);
numbers.add(s1);
if (handler < 1) {
total4 = Double.parseDouble(currentcalc.getText().toString());
} else {
int i = 0;
for (i = 0; i < handler; i++) {
switch (operators.get(i)) {
case '/':
total3 = numbers.get(i) / numbers.get(i + 1);
total4 = total3;
numbers.remove(i + 1);
numbers.set(i, total4);
operators.remove(i);
handler--;
i--;
break;
}
}
for (i = 0; i < handler; i++) {
switch (operators.get(i)) {
case '*':
total3 = numbers.get(i) * numbers.get(i + 1);
total4 = total3;
numbers.remove(i + 1);
numbers.set(i, total4);
operators.remove(i);
handler--;
i--;
break;
}
}
for (i = 0; i < handler; i++) {
switch (operators.get(i)) {
case '+':
total3 = numbers.get(i) + numbers.get(i + 1);
total4 = total3;
numbers.remove(i + 1);
numbers.set(i, total4);
operators.remove(i);
break;
case '-':
total3 = numbers.get(i) - numbers.get(i + 1);
total4 = total3;
numbers.remove(i + 1);
numbers.set(i, total4);
operators.remove(i);
break;
}
handler--;
i--;
}
}
et1.setText(Double.toString(total4));
resettext = 1;
}
Following your result() method, total4 is set to 0.0 at the beginning, and no code ever changes it when the "." operator is encountered.
The bug is that you are treating "." as an operator. Have special code in your parsing loop to treat it as part of the number. You need to change the line if (!Character.isDigit(c)) {, and handle the maths logic.
If you are not required to implement any specific algorithm then you can use:
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("js");
Object result = engine.eval("3+4");
Otherwise you may want to look at the following:
Shunting Yard Algorithm