How to get supported display refresh rates on Linux? - c++

drmModeModeInfo structure from DRM contains uint32_t vrefresh; field, and the values are actually good there i.e. I’m getting 24-75Hz for different video modes. But refresh rates aren’t integers, they’re rational numbers, right now for my display the value is 59997/1000.
Is it possible to get the precise numbers on Linux? Or at least a floating point value?

The numerator is drmModeModeInfo::clock * 1000, the clock field is in kilohertz and we need Hz for the formula.
The denominator is the product of drmModeModeInfo::htotal and drmModeModeInfo::vtotal fields.
For better result, I simplify the rational by dividing both numerator and denominator by their greatest common divisor. For this part, I have used an algorithm from Wikipedia.
I’m not sure if current displays support signal frequencies above 2^32 Hz = 4.29 GHz, but even if they do not, future ones may do so, i.e. you better use 64-bit integer math there.

I simply use this:
drmModeModeInfoPtr mode = 0;
.
.
double freq = mode->clock * 1000.0f / (mode->htotal * mode->vtotal);
freq = round(freq * 1000.0f) / 1000.0f;

Related

SAS Getting Simple Calculation Wrong

I can't believe I have never had this issue before (nor can I find anyone else with the same issue) but today I have just discovered that SAS sometimes gets simple calculations wrong!?! I noticed that one of my records wasn't getting picked up in the right group based on a value being <3.6 and thought there must be something strange in my data with decimal places. But on investigation I found it was just because SAS was calculating the value wrong! For some reason that I can't fathom, it seems that SAS calculates 90 - 86.4 as 3.59999999999999!!! Simple program below to show this:
code
output
If I alter the calculation to 10 - 6.4 I get the correct value of 3.6000 but for some reason this one is coming out wrong. Could there be some mad setting that is wrong in my installation? I tried both SAS EG and Base SAS and both have the same issue. I feel like I'm going mad! Any help appreciated.
Thanks.
Floating point arithmetic, in any language, will have this same issue. The same issue is possible to understand in human terms, assuming the human doesn't have a concept of infinite. If you only write down 4 digits for your decimals, for example, then:
1 - (1/3) - (1/3) - (1/3)
That's zero, right?
1 - 0.3333 = 0.6667
0.6667 - 0.3333 = 0.3334
0.3334 - 0.3333 = 0.0001
Nope! Computers do the same thing, but in binary, so they have a different (and larger) set of "problem" numbers. 1/10, for example, is not representable in binary - so adding or subtracting 0.1 is not always a "neat" operation like it is in decimal.
SAS uses 8 byte floating points, and so it gets ~15 digits of accuracy. Assuming you're not working in a field where 15 digits of accuracy is needed, you should simply round.
if round(value,.01) ge 3.6 then ... ;
Most of the time this isn't needed, but strictly speaking you should always compare rounded numbers whenever using floating point numbers (as SAS does). Integers are safe, but if you're working with 0.1 etc., use ROUND or FUZZ for integers.
Sorry Cannot replicate your findings.
data x;
a=90-86.4;
run;
Gives the correct result. Are you using any formats or put function. Share the complete code.

SAS ceil/floor issues using big numbers and wanting to ceil/floor to the nearest 10,000

I have one number which I need to find the ceiling and the floor value of (203,400) in order to use this number to create a weighted average. From this number I want: 200,000 and 210,000 so the code I was using that doesn't work is:
S1CovA_ceil = ceil(S1CovA,10000);
S1CovA_floor = floor(S1CovA,10000);
When I run this program, I get these errors:
ERROR 72-185: The CEIL function call has too many arguments.
ERROR 72-185: The FLOOR function call has too many arguments.
Does anybody know a way around this or different SAS code I could use?
CEIL and FLOOR only remove decimals - specifically rounding to integer value. If you want it rounded to (above/below) multiple of 10,000, you have to do it a bit more complicatedly:
S1CovA_ceil = ceil(s1covA/10000)*10000;
And the same for floor. Basically you have to divide it by the desired rounding level, round the rest with ceil/floor, and then multiply back.
Unfortunately, as far as I'm aware, SAS doesn't allow rounding in a particular direction except for straight integer rounding.
You can also use the round() function...
%LET ROUNDTO = 10000 ;
data xyz ;
S1CovA_ceil = round(S1CovA+(&ROUNDTO / 2),&ROUNDTO) ;
S1CovA_floor = round(S1CovA-(&ROUNDTO / 2),&ROUNDTO) ;
run ;
Try
S1CovA_ceil = ceil(S1CovA/10000)*10000;
S1CovA_floor = floor(S1CovA/10000)*10000;

What's the best way to round monetary amounts to the nearest nickel, quarter, $1, $5, etc. denominations?

Canada announced that they will no longer mint pennies and the U.S. Treasury is strongly contemplating following suit! That implies that monetary amounts will have to be rounded to the nearest nickel, thus requiring a lot of programming modifications!.. In the pawnshop business, we've been rounding loan amounts to the nearest $5 denominations, e.g. 50, 55, 60.. when the calculated loan falls between $50 and $100, to the nearest $10 denomination above $100, etc. Its common practice in order to minimize the use of smaller denomination bills. So what is a good algorithm for rounding to the nearest desired denomination?
In SQL, could I create a user-defined datatype to round to n-denomination, or is it better to leave the decimal(8,2) datatype alone and round with a function?
Assuming that you have your numbers as something like: 44.32, then all you need to do (this is pseudocode, the implementation in c++ should be trivial):
findmod = (num_to_be_changed*100)%5
if findmod <= 2
new_num = num_to_be_changed - findmod
else
new_num = num_to_be_changed + (5 - findmod)
end
new_num = new_num/100
I'd be tempted to use in SQL:
new_val = ROUND(old_value * 20) / 20;
And when nickels go the way of cents, then:
new_val = ROUND(old_value * 10) / 10;
This works fine in SQL with DECIMAL or NUMERIC values; it also works well with SQL FLOAT and a little less reliably with SQL SMALLFLOAT (simply because SMALLFLOAT may only have about 6 decimal digits of accuracy). The same basic technique can be used in C++ if the old_value is a double (more dubiously if it is a float, for the same reason that SQL SMALLFLOAT is problematic). In C++ or C, you'd use the <cmath> or <math.h> header to obtain a declaration for the function round() or roundf(). If you're using ESQL/C and dec_t, then you need decround(&dec_value, 0);.
In ESQL/C, you have provide the number of places to round to, and you'd have to code the multiply and divide, too. Assuming you have a decimal value dec_20 somewhere containing the value 20, you'd write:
dec_t new_val;
decmul(&old_val, &dec_20, &new_val);
decround(&new_val, 0);
decdiv(&new_val, &dec_20, &new_val);
You might error check decmul() and decdiv(); there is no return value from decround() to do an error check on. It is safe to use one of the inputs as the output in the last line.
Not a technical answer per se to the question, but a point to be considered. You may find that your "programmatic modifications" are illusory.
When Australia phased out 1 and 2 cent coins in the 1990s, rounding of amounts was only performed on cash transactions, and this is still the case. Card payments are charged to the cent. Likewise, telephone and other utility bills are charged to the cent, but rounded to the nearest 5c when (and only when) paid in cash over the counter. And of course, share trading and currency exchange continue to be dealt with in fractions of cents or pennies.
So if you can assume that the number of cash transactions rounded down (those ending in 1, 2, 6 or 7c) is roughly the same as the number rounded up (3, 4, 8 or 9c), then the only effect is that the cash register may be out by a few cents at the end of the day. In fact, it is more likely to be up a few cents, because all single item transactions will be rounded up (e.g. every $3.99 purchase is $4.00 in the till.)
There do not have to be any programming changes to support the phase-out of pennies. You can choose to show the rounded amount on printed dockets, but it's not correct to presume anyone is lumbered with a mini Y2K or Euro implementation problem.

Calculating a Random for C++

This is probably a super easy question, but I just wanted to make 10000% sure before I did it.
Basically Im doing a formula for a program, it takes some certain values and does things when them.....etc..
Anyways Lets say I have some values called:
N
Links_Retrieved
True_Links
True_Retrieved.
I also have a % "scalar" ill call it, for this example lets say the % scalar is 10%.
Links Retrieved is ALWAYS half of N, so that's easy to calculate.
BUT I want True_Links to be ANYWHERE from 1-10% of Links_Retrieved.
Then I want True_Retrieved to be anywhere from The True_Links to 15% of Links_Retrieved.
How would I do this? would it be something like
True_Link=(((rand()%(Scalar(10%)-1))+1)/100);
?
I would divide by 100 to get the "percent" value IE .1 so it's be anywhere from .01 to .1?
and to do the True_retrieved it'd be
True_Retrieved=(rand()%(.15-True_Link))+True_Link;
am I doing this correct or am I WAYYYY off?
thanks
rand() is a very simple Random Number Generator. The Boost libraries include Boost.Random. In addition to random number generators, Boost.Random provides a set of classes to generate specific distirbutions. It sounds like you would want a distribution that's random between 1% and 10%, i.e. 0.01 and 0.1. That's done with boost::random::uniform_real(0.01, 0.1).
Maybe it would be better to use advanced random generator like Mersenne Twister.
rand() produces values between 0.0 and 1.0 inclusive, you have to scale that output to the interval you want. To get a value fact1 between 0.01 and 0.1 (1%-10%) you'd do:
perc1 = (rand()/RAND_MAX)*9.0+1.0; //percentage 1-10 on the 0-100 scale
fact1 = perc1/100.0; //factor 0.01 - 0.1 on the 0-1 scale
to get a value between perc1 and 0.15 you'd do:
percrange = (15.0 - perc1);
perc2 = (rand()/RAND_MAX)*percrange + perc1;
fact2 = perc2/100.0;
so your values become:
True_Links = fact1*Links_Retrieved;
True_Retrieved = fact2*Links_Retrieved;
This is sort-of-pseudocode. You should make sure parc1, perc2, fact1, fact2 and percrange are floating point values, and the final multiplications are done in floating point and rounded to integer numbers.

Random number generator that produces a power-law distribution?

I'm writing some tests for a C++ command line Linux app. I'd like to generate a bunch of integers with a power-law/long-tail distribution. Meaning, I get a some numbers very frequently but most of them relatively infrequently.
Ideally there would just be some magic equations I could use with rand() or one of the stdlib random functions. If not, an easy to use chunk of C/C++ would be great.
Thanks!
This page at Wolfram MathWorld discusses how to get a power-law distribution from a uniform distribution (which is what most random number generators provide).
The short answer (derivation at the above link):
x = [(x1^(n+1) - x0^(n+1))*y + x0^(n+1)]^(1/(n+1))
where y is a uniform variate, n is the distribution power, x0 and x1 define the range of the distribution, and x is your power-law distributed variate.
If you know the distribution you want (called the Probability Distribution Function (PDF)) and have it properly normalized, you can integrate it to get the Cumulative Distribution Function (CDF), then invert the CDF (if possible) to get the transformation you need from uniform [0,1] distribution to your desired.
So you start by defining the distribution you want.
P = F(x)
(for x in [0,1]) then integrated to give
C(y) = \int_0^y F(x) dx
If this can be inverted you get
y = F^{-1}(C)
So call rand() and plug the result in as C in the last line and use y.
This result is called the Fundamental Theorem of Sampling. This is a hassle because of the normalization requirement and the need to analytically invert the function.
Alternately you can use a rejection technique: throw a number uniformly in the desired range, then throw another number and compare to the PDF at the location indeicated by your first throw. Reject if the second throw exceeds the PDF. Tends to be inefficient for PDFs with a lot of low probability region, like those with long tails...
An intermediate approach involves inverting the CDF by brute force: you store the CDF as a lookup table, and do a reverse lookup to get the result.
The real stinker here is that simple x^-n distributions are non-normalizable on the range [0,1], so you can't use the sampling theorem. Try (x+1)^-n instead...
I just wanted to carry out an actual simulation as a complement to the (rightfully) accepted answer. Although in R, the code is so simple as to be (pseudo)-pseudo-code.
One tiny difference between the Wolfram MathWorld formula in the accepted answer and other, perhaps more common, equations is the fact that the power law exponent n (which is typically denoted as alpha) does not carry an explicit negative sign. So the chosen alpha value has to be negative, and typically between 2 and 3.
x0 and x1 stand for the lower and upper limits of the distribution.
So here it is:
set.seed(0)
x1 = 5 # Maximum value
x0 = 0.1 # It can't be zero; otherwise X^0^(neg) is 1/0.
alpha = -2.5 # It has to be negative.
y = runif(1e7) # Number of samples
x = ((x1^(alpha+1) - x0^(alpha+1))*y + x0^(alpha+1))^(1/(alpha+1))
plot(density(x), ylab="log density x", col=2)
or plotted in logarithmic scale:
plot(density(x), log="xy", ylab="log density x", col=2)
Here is the summary of the data:
> summary(x)
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.1000 0.1208 0.1584 0.2590 0.2511 4.9388
I can't comment on the math required to produce a power law distribution (the other posts have suggestions) but I would suggest you familiarize yourself with the TR1 C++ Standard Library random number facilities in <random>. These provide more functionality than std::rand and std::srand. The new system specifies a modular API for generators, engines and distributions and supplies a bunch of presets.
The included distribution presets are:
uniform_int
bernoulli_distribution
geometric_distribution
poisson_distribution
binomial_distribution
uniform_real
exponential_distribution
normal_distribution
gamma_distribution
When you define your power law distribution, you should be able to plug it in with existing generators and engines. The book The C++ Standard Library Extensions by Pete Becker has a great chapter on <random>.
Here is an article about how to create other distributions (with examples for Cauchy, Chi-squared, Student t and Snedecor F)