C++/Rate question - Hz
Expert: Ralph McArdell - 2/27/2008
QuestionI have a line of code that says
if(g100Hzframectr%100==0){...
which is defined in the comment as processing at 1 hz and another if(g100Hzframectr%10==0){... defined as 10 hz. This makes sense, but a third line says if(g100Hzframectr%50==2){...
I think I am misunderstanding the % and how it is being used, and ==0 vs. ==2.
Can you help?
AnswerYes and no.
I cannot state what the intention of the code is as I do not have enough information, particularly I have no real idea what the value of g100Hzframectr represents other than it is prefixed by a g, which is sometimes used to indicate a global variable (in which case I may query whether this is a good idea as good design tries to minimise the use of global) and the name suggests it relates in some way to a 100Hz frequency and some frame something (ctr - centre, control, ... ??).
However I can explain what the % operator in C and C++ does and therefore which values of g100Hzframectr will give true values to the if statements' Boolean expressions.
The C and C++ % operator is the modulus operator. It is useful only for integer values. The modulus is the remainder of one value divided by another: 10 modulus 3 gives 1; that is 10 / 3 is 3 remainder 1. In C or C++ we would then write 10 % 3 and get a result of 1.
One point about modulus operations is that their results are cyclic for increasing values of the left hand side for the same right hand side value:
0 % 3 == 0
1 % 3 == 1
2 % 3 == 2
3 % 3 == 0
4 % 3 == 1
5 % 3 == 2
6 % 3 == 0
7 % 3 == 1
8 % 3 == 2
.
.
.
Notice that the result is zero for a right hand side value of zero or any value that is a multiple of the right hand side (OK so strictly zero is a multiple of any value I suppose, but I shall keep it separate as it is often a forgotten case). This is to be expected: If one value is a multiple of another dividing it by that value will by definition have a zero remainder: a * b = c => c / b = a with 0 remainder.
Notice also that the nonzero remainder values can be considered as offset from 0 and multiples of the right hand side value. Thus in the above examples a result of 2 occurs for 0 + 2 and (multiple of 3) + 2: 0+2, 3+2, 6+2, ...
Note that modulus only applies to integer arithmetic because when we divide using integer arithmetic (as we were taught in school) we specify the result in two, whole number (i.e. integer) parts:
- the value of the number of times one value goes into another
- the value of the remainder
This is not the case for real numbers, in which dividing one real number by another yields a single real number result.
OK so that is how the %, modulus or remainder, operator works. So how does it apply to the three if statements you showed?
First you have an if with the condition:
g100Hzframectr%100==0
This means that the condition will be true for values of g100Hzframectr that are 0 and multiples of 100:
0, 100, 200, ..., 1000, 1100, ..., 2000, 2100, ..., 10000, ...
Next you have an if with the condition:
g100Hzframectr%10==0
This means that the condition will be true for values of g100Hzframectr that are 0 and multiples of 10:
0, 10, 20, ..., 100, 110, ..., 200, 210, ..., 1000, 1010, ...
And finally, the one that has you confused, you have an if with the condition:
g100Hzframectr%50==2
This means that the condition will be true for values of g100Hzframectr that are 2 and (multiples of 50) + 2:
2, 52, 102, 152, 202, ..., 1002, 1052, 1102, ..., 2002, ...
So I would guess that maybe your understanding of % is OK and the person who wrote the code was confused as the final results look a bit strange.
I would try to find out what the code should be doing then see if it actually is doing that.
Here is a quick and dirty C++ program to check the values each if statement would match (i.e. all values for which the if condition is true for):
#include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>
// Type alias for values of g100Hzframectr & related objects
typedef unsigned int ValueType;
// Type alias for collections of matched ValueType values
typedef std::vector<unsigned int> MatchedValuesType;
// Functor class used with the std::for_each algorithm
// to display a single value from a collection of values.
//
// Instances are stateful, but copyable.
//
// Each instance keeps track of the width of the value display
// field and the number of fields that can fit on one line.
//
// Instances are constructed from a field width value and
// a display line length value (both in characters).
//
// The fields per line value is calculated from these values.
class PrintValue
{
unsigned int iCount; // Count of values on current line
unsigned int iFieldWidth; // Width of value display field
unsigned int iFieldsPerLine; // Value display fields per line
public:
// Construct from field width and line length.
// Values default to a width of 5 characters and
// a line length of 72 characters.
PrintValue(unsigned int fieldWidth=5, unsigned int lineLength=72)
: iCount(0)
, iFieldWidth(fieldWidth)
, iFieldsPerLine( lineLength / fieldWidth )
{}
// Function call operator.
// Takes value to be displayed and inserts it into the
// std::cout stream specifying a field width of iFieldWidth.
// Increments the count of values displayed on current line.
// If this count equals iFieldsPerLine then resets count to
// zero and starts a new line.
void operator()(ValueType v)
{
std::cout << std::setw(iFieldWidth) << v;
++iCount;
if ( iCount == iFieldsPerLine )
{
iCount = 0;
std::cout << '\n';
}
}
};
// Main program entry point.
int main()
{
// Collections for storing matched values for each if condition
MatchedValuesType matched_mod_100_eq_0;
MatchedValuesType matched_mod_10_eq_0;
MatchedValuesType matched_mod_50_eq_2;
// Maximum value we will consider for g100Hzframectr
ValueType const MaxValue(1000);
// Loop setting g100Hzframectr from zero to MaxValue
for ( ValueType g100Hzframectr=0
; g100Hzframectr<=MaxValue
; ++g100Hzframectr
)
{
// Test each value against each if condition.
// For each true case add value to collection of
// matched values for specific if condition:
if ( g100Hzframectr % 100 == 0)
{
matched_mod_100_eq_0.push_back( g100Hzframectr );
}
if ( g100Hzframectr % 10 == 0)
{
matched_mod_10_eq_0.push_back( g100Hzframectr );
}
if ( g100Hzframectr % 50 == 2)
{
matched_mod_50_eq_2.push_back( g100Hzframectr );
}
}
// Write out matching values for each
// if condition collected above:
//
// If you wish to use fieldWidth or lineLength
// other than the defaults then use one of the
// following forms as the 3rd parameter to
// std::for_each:
//
// PrintValue( requriedFieldWidth )
//
// for a specific field width with default line length or
//
// PrintValue( requriedFieldWidth, requiredLineLength )
//
// to specify both fieldWidth and lineLength
//
std::cout << "g100Hzframectr % 100 == 0 matched values:\n";
std::for_each ( matched_mod_100_eq_0.begin()
, matched_mod_100_eq_0.end()
, PrintValue()
);
std::cout << "\n\ng100Hzframectr % 10 == 0 matched values:\n";
std::for_each ( matched_mod_10_eq_0.begin()
, matched_mod_10_eq_0.end()
, PrintValue()
);
std::cout << "\n\ng100Hzframectr % 50 == 2 matched values:\n";
std::for_each ( matched_mod_50_eq_2.begin()
, matched_mod_50_eq_2.end()
, PrintValue()
);
std::cout << std::endl;
}
The program assumes a fairly ISO standard C++ implementation. In particular it assumes access to an reasonably ISO standard C++ library, making use of standard collections and algorithms. I compiled the code and ran it using Microsoft Visual C++ 2005 (Win32 debug build) on Microsoft Windows Vista Business x64 edition and under g++ 4.1.3 on x64 Ubuntu Linux Desktop version 7.10.
The idea is to iterate through values of g100Hzframectr from 0 to some maximum value (currently set to 1000). For each value the if statements you showed in your question are used. Each time the condition is true and the if clause is executed the value of g100Hzframectr is added to a collection of matching values for that if statement condition. After iterating through g100Hzframectr values and collecting matching values completes the matched values for each of the three conditions are displayed one after the other. The output should look like so:
g100Hzframectr % 100 == 0 matched values:
0 100 200 300 400 500 600 700 800 900 1000
g100Hzframectr % 10 == 0 matched values:
0 10 20 30 40 50 60 70 80 90 100 110 120 130
140 150 160 170 180 190 200 210 220 230 240 250 260 270
280 290 300 310 320 330 340 350 360 370 380 390 400 410
420 430 440 450 460 470 480 490 500 510 520 530 540 550
560 570 580 590 600 610 620 630 640 650 660 670 680 690
700 710 720 730 740 750 760 770 780 790 800 810 820 830
840 850 860 870 880 890 900 910 920 930 940 950 960 970
980 990 1000
g100Hzframectr % 50 == 2 matched values:
2 52 102 152 202 252 302 352 402 452 502 552 602 652
702 752 802 852 902 952
Hope this helps.