I am working on a SQL server project to make conversion between two types of car prices (eg, x is the original price, y is the dealer asking price) based on some rules, so that for every given dealer asking price y, I can get a corresponding original price x. The conversion rule I am having trouble with is this one: x + 5*ceiling(x/100) + some constant c = y, x=?
(It's more of a math problem actually. For example, if the rule is as easy as x + 10 = y, then x = y-10.)
Indeed, it's a math problem, that should be asked on Mathematics Stack Exchange.
That said, note that in the equation x+ceil(x)+c=y, x and y-c differ only by an integer (that depends on x). And since x+ceil(x) is an increasing function of x, if there is a solution it's unique.
Another remark:
for x in (0,1], x+ceil(x) lies in (1,2].
for x in (1,2], x+ceil(x) lies in (3,4].
...
That is, there is a solution only if y-c is in (2n-1,2n] for some integer n. And then, x=y-c-n.
How do we find n? Well, y-c in (2n-1,2n] iff (y-c)/2 in (n-1/2,n]. So we must have n=ceil((y-c)/2).
It's not much more difficult for the equation x+5ceil(x/100)=y-c.
Now,
for x in (0,100], x+5ceil(x/100) in (5,105]
for x in (100,200], x+5ceil(x/100) in (110,210]
...
for x in (100(n-1), 100n], x+5ceil(x/100) in (105n-100,105n]
Again, some values can't be reached, and if there is a solution, it's unique.
And if y-c lies in (105n-100,105n] for some n, then x=y-c-5n.
Of course, you want to find n. Note that y-c in (105n-100,105n] iff (y-c)/105 is in (n-100/105,n], which is a subset of (n-1,n]. So if there is a solution, you must have n=ceil((y-c)/105).
Not a complete answer but for the simple case of
Y = X + Ceiling(X)
declare #X float = 3.7
declare #Y float = 0.0
SELECT #y = #x + ceiling(#x)
SELECT CASE
WHEN (#y -floor(#y)) = 0 THEN #y/2
ELSE (#y - (#y -floor(#y)) - 1)/2 + (#y -floor(#y))
END XValue
This works for all values of X that I've tested. The first case is for when X is a whole integer.
EDIT
For your case of Y = X + 5*CEILING(X)/100 we can surmise that if X is an integer then Y = X + 5/100 * X => 1.05 * X, if X is not an integer then y = X + 5/100(X+1) => 1.05*X + 0.05
So I think the following works for your case:
declare #X float = 3.1
declare #Y float = 0.0
SELECT #y = #x + 5*ceiling(#X)/100
SELECT CASE WHEN (ROUND(#y/1.05,0) = #y/1.05) THEN #y / 1.05
ELSE ROUND((#y - 0.05) / 1.05,2) END
For your case with a constant, I can't see how to solve this without knowing the constant.
Related
Given some arbitrary geometry in the standard ESPG-4326 (latitude & longitude), that was converted to an MVT tile geometry with ST_AsMvtGeom() postgis function (in web mercator 3857), I need to convert it back to the 4326 using postgis functionality.
select st_astext(
st_asmvtgeom(
st_transform(ST_GeomFromText('POINT(-73.985130 40.748817)', 4326), 3857),
st_tileenvelope(8, 75, 96),
extent := 4096, buffer := 0, clip_geom := true));
The above returns POINT(1591 890). I need to write a similar SQL statement to convert it back to POINT(-73.985130 40.748817) using the inputs of 'POINT(1591 890)', 8, 75, 96 (geometry + tile coordinates). The result would obviously be slightly different from the original.
This seems to do the job. The st_tileenvelope() is a bit of an overkill, because it is only needed to compute the width/height of a tile in meters (i.e. 40075000/(2^z)). Also, the last st_transform() step is not really needed - the resulting geometry is already in a usable format and has SRID attached to it.
CREATE OR REPLACE FUNCTION decode_mvt_geom(geom geometry, z int, x int, y int, extent int) RETURNS geometry AS $$
SELECT st_transform(
st_scale(
st_translate(geom, extent * (x - 2 ^ (z - 1)), extent * (y - 2 ^ (z - 1)))
, (st_xmax(st_tileenvelope(z, x, y)) - st_xmin(st_tileenvelope(z, x, y))) / extent
, -(st_ymax(st_tileenvelope(z, x, y)) - st_ymin(st_tileenvelope(z, x, y))) / extent
)
, 4326)
$$ COST 1 LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE;
A simpler function without the final projection transformation could be this:
CREATE OR REPLACE FUNCTION decode_mvt_geom(geom geometry, z int, x int, y int, extent int) RETURNS geometry AS $$
SELECT st_scale(
st_translate(geom, extent * (x - 2 ^ (z - 1)), -extent * (y - 2 ^ (z - 1))),
40075016.6855785 / (2 ^ z) / extent,
40075016.6855785 / (2 ^ z) / extent
)
$$ COST 1 LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE;
Consider the overly simplistic example: POINT(0 0) and LINESTRING (1 -10, 1 10)
The closest point on the line to the POINT would be 1, 0.
How would one determine this in TSQL? My simple, not entirely accurate, approach was to make a linestring (POINT POINT) and extend out the X coord of one coords until the two linestrings intersected.
So:
linestring (0 0, 0.25 0) (no intersect)
linestring (0 0, 0.5 0) (no intersect)
linestring (0 0, 0.75 0) (no intersect)
linestring (0 0, 1 0) (intersection - so 1 0 is the point closest to POINT
This quasi worked, but doesn't seem to the most bestest/more performant way of accomplishing this.
For example, one inefficiency is that I move it one direction (positive increments), and if there was no match (after x attempts), then I would start over, but with negative increments.
To optimize, I tried moving in larger steps, then when intersected (probably went past the point), I backed off 1 increment and started from there with a smaller increment. I did this a couple of times - instead of going in tiny tiny increments so as not to overshoot by too much.
One acceptable assumption based on my processing that the POINT will be next to (left/right) of the LINESTRING.
Another acceptable assumption is that the LINESTRING will be fairly "perpendicular" to the POINT.
I think you can do this mathematically rather than with a brute-force iterative algorithm.
There is a post to get closest point to a line that describes the method.
I converted this method to SQL which returns the correct value (1,0). Your 'trivial' example is actually a bit of an edge case (vertical line with infinite slope) so it seems robust.
I also tested the source code with this example: https://www.desmos.com/calculator/iz07az84f5 and using the input for the line of (-1,2) (3,0) and a point at (2,2) got the correct answer (1.4, 0.8).
SQL code (also in SQL Fiddle at http://sqlfiddle.com/#!6/d87aa/15)
DECLARE #x int, #y int, #x1 int, #y1 int, #x2 int, #y2 int
DECLARE #atb2 float, #atp_dot_atb float
DECLARE #t float
--SELECT #x=0, #y=0
--SELECT #x1=1, #y1=10, #x2=1, #y2=-10
SELECT #x=2, #y=2
SELECT #x1=-1, #y1=2, #x2=3, #y2=0
SELECT #atb2 = SQUARE(#x2-#x1) + SQUARE(#y2-#y1) -- Basically finding the squared magnitude of a_to_b
SELECT #atp_dot_atb = (#x-#x1)*(#x2-#x1) + (#y-#y1)*(#y2-#y1) -- The dot product of a_to_p and a_to_b
SELECT #t = #atp_dot_atb / #atb2 -- The normalized "distance" from a to your closest point
SELECT #x1 + (#x2-#x1)*#t, #y1 + (#y2-#y1)*#t --Add the distance to A, moving towards B
I am new to C programming, in fact programming at all, and recently learn the use of macros with regard to preprocessor directives. Although I am getting more familiar with it the following exercise that I got from a textbook stumbles me since I do not get the solution or the general "take-away lesson" from it.
Before I wrote this question here, I tried to execute the code myself by adding some printf() in order to obtain the correct answers but it does not even compile. Now, before I write down the question and code I want to make it explicit that this is a self-learning question and that I do not want to offend people here with a question that many will find trivial. I just want to understand what is going on.
The code is as follows
int x=2, y=3, a=4,b=5;
#define MAX(x, y) x > y x : y
int c,d,e,f;
c = MAX( a, 3 );
d = MAX( y, x );
e = MAX( ++x, 1 );
f = MAX( b, MAX (6, 7) );
I am asked to give the values of c,d,e and f. There is an additional hint that although it is named that way the above macro is NOT the maximum operator. Therefore, I don't think the "obvious" guess of e.g. max(a,3) = 4 is correct. Consequently, I don't know what is going on.
EDIT: I forgot to mention: I know that there are parentheses missing for the correct use. But I am specifically asked to evaluate the terms without them. Therefore I am confused since I do not know exactly how the results change and the function behave without those included.
Expanding the macro as-is, we get the following:
Original Expanded
-------- --------
c = MAX( a, 3 ); c = a>3 a : 3;
d = MAX( y, x ); d = y>x y : x;
e = MAX( ++x, 1 ); e = ++x>1 ++x : 1;
f = MAX( b, MAX (6, 7) ); f = b>MAX (6, 7) b : MAX (6, 7);
f = b>6>7 6 : 7 b : 6>7 6 : 7;
Macro expansion is just dumb text substitution - syntax, scope, precedence, associativity, values, side effects, etc., are simply not taken into account when a macro is expanded (macro expansion occurs before the source code is fed to the compiler proper).
Obviously, none of the expanded expressions above will compile. For that to happen, we need to fix the MAX macro by defining it as
#define MAX( x, y ) x>y ? x : y
Now we get the following:
Original Expanded
-------- --------
c = MAX( a, 3 ); c = a>3 ? a : 3;
d = MAX( y, x ); d = y>x ? y : x;
e = MAX( ++x, 1 ); e = ++x>1 ? ++x : 1;
f = MAX( b, MAX (6, 7) ); f = b>MAX (6, 7) ? b : MAX (6, 7);
f = b>6>7 ? 6 : 7 ? b : 6>7 ? 6 : 7;
Better. The expanded expressions above will compile, but the last two don't do anything like what you expect them to. e won't get the max of x and 1, it will either get x+2 or 1 (? introduces a sequence point, so the behavior isn't undefined). f gets ... something, can't remember the associativity of > and ?: offhand, not really willing to dig it up.
Again, macros don't take precedence and associativity into account when expanding their arguments. Imagine we write a macro CUBE that does the following:
#define CUBE(x) x * x * x
and we call it as
y = CUBE( 2 + 3 );
That expands to
y = 2 + 3 * 2 + 3 * 2 + 3;
which gives us the value 17, when we were probably expecting 125.
The right way to define the MAX macro is
#define MAX( x, y ) ((x) > (y) ? (x) : (y))
We not only parenthesize each argument, we parenthesize the entire expression. This way, precedence and associativity are preserved not only if you pass complex expressions as arguments, but also if you pass this macro as an argument to another one (as in the last example):
Original Expanded
-------- --------
c = MAX( a, 3 ); c = ((a) > (3) ? (a) : (3));
d = MAX( y, x ); d = ((y) > (x) ? (y) : (x));
e = MAX( ++x, 1 ); e = ((++x) > (1) ? (++x) : (1));
f = MAX( b, MAX (6, 7) ); f = ((b) > (MAX (6, 7)) ? (b) : (MAX (6, 7)));
f = ((b) > ((6) > (7) ? (6) : (7)) ? (b) : ((6) > (7) ? (6) : (7)));
This time, f will be evaluated like you expect it to be.
The evaluation of e is still problematic (++x can still be evaluated twice). This is a problem in general with macros that expand their arguments more than once - arguments that have side effects can be evaluated multiple times, which will lead to wrong answers or undefined behavior.
Incorrect use of ternary operator.
#define MAX(x,y) x>y x : y
Should be:
#define MAX(x,y) (x>y) ? x : y
And to allow for more complex expressions:
#define MAX(x,y) (((x)>(y)) ? (x) : (y))
You mention that you don't know what is going on. There is only way - run only the preprocessor.
What compiler are you using? Assuming gcc/clang you can -
gcc -E filename.c
This will only run the preprocessor and let you analyze what is going on.
BTW you code doesn't compile because you made a mistake with the ternary operator - should be x > y ? x : y.
I'm having trouble running this formula further down in the code, x. In short, I am trying to run this though the forloop to simulate this happening 1000 times.The, hopefully adding up the amount of time TF is true and TS is true. I am getting the error that I'm missing a TRUE/FALSE statement, and tried reworking the function and am still quite stuck. Any help or advice would be greatly appreciated.
#Parameters
c=0.10 #colonization rate
A=10 #Area of all islands(km^2)
d=100 #Distance from host to target (A-T)
s=0.5 #magnitude of distance
d0=100 #Specific "half distance" for dispersal(km)
C1 = c*A*exp(-d/d0) #Mainland to Target colonization
TS=1 #Target Success
TF=0 #Target Failure
Z =runif(1,0,1)
x <- C1*A
for(i in 1:1000)
if(x[i] <= Z)
print("TS")
if(x[i] >= Z)
print("TF")
The problem is that x is just 1 scalar value but you're indexing it as if it has 1,000 elements.
x
[1] 3.678794
Based on your description it sounds like you just wanted to run your code 1,000 times. This does that:
for(i in 1:1000) {
c=0.10 #colonization rate
A=10 #Area of all islands(km^2)
d=100 #Distance from host to target (A-T)
s=0.5 #magnitude of distance
d0=100 #Specific "half distance" for dispersal(km)
C1 = c*A*exp(-d/d0) #Mainland to Target colonization
TS=1 #Target Success
TF=0 #Target Failure
Z =runif(1,0,1)
x <- C1*A
if(x <= Z) {
print("TS")
}
if(x >= Z){
print("TF")
}
}
With the way you've written code 'x' is not an array but a value, so you can't dereference it the way you've done right now.
I have the following query:
DECLARE #A as numeric(36,14) = 480
DECLARE #B as numeric(36,14) = 1
select #B/#A
select cast(#B as decimal)/cast(#A as decimal)
Why does the first calculation returns 0.002083 and the second one returns 0.00208333333333333?
IsnĀ“t numeric(36,14) good enough to have a good precision (just as the second query)?
If I use only numeric, instead of numeric(36,14), I have a good precision again:
select cast(#B as numeric)/cast(#A as numeric)
You can calculate precision and scale by yourself using this documentation from SQL Server Books online.
I tried to calculate precision and scale for your case (operation=division, p=36, s=14) and I got a pretty strange results...
precision of the result: [p1 - s1 + s2 + max(6, s1 + p2 + 1)] -> 36-14+14+max(6,14+36+1)=36+51=87
scale of the result : [max(6, s1 + p2 + 1)] -> max(6,14+36+1)=51
In this situation precision is greater than 38 and in this case (as stated in the documentation)
*The result precision and scale have an absolute maximum of 38. When a result precision is greater than 38, the corresponding scale is
reduced to prevent the integral part of a result from being truncated.
scale must be reduced by (87-38=) 49, that is (51-49=) 2 ...
I think that minimum scale length is 6 (because of expression scale=[max(6, s1 + p2 + 1)]) and it can't be reduced lower than 6 - that we have as a result (0.002083).
Just contributing for the understanding of the problem (going deeper on #Andrey answer), the things could be tricky, depending on the order of calculations.
Consider the variables:^
DECLARE #A as NUMERIC(36,19) = 100
DECLARE #B as NUMERIC(36,19) = 480
DECLARE #C as NUMERIC(36,19) = 100
Calculating A/B*C
If you want to calculate A/B*C, using the formulaes, we have:
A/B is of type NUMERIC(38,6) --> as calculated by #Andrey
The result will be 0.208333 (with scale of 6)
Multiplying by 100, we will get 20.833300
Calculating A*C/B
The result of A*C is 10000 of type NUMERIC(38,6). Diving by C, the result will be 20.833333 of type NUMERIC(38,6)
Then, the result may vary depending on the order of calculation (the same problem was pointed in https://dba.stackexchange.com/questions/77664/how-does-sql-server-determine-precision-scale).