2x + 4y + 6z = 1200
x + y + z = 300
how can I find the possible x, y, z integer values in a c# method?, I am trying to find a better solution instead of using brute force nested for loops since it is not a good solution.
public List<Tuple<int, int, int>> Calculate()
{
var result = new List<Tuple<int, int, int>>();
int maxValue = 300;
for(int i = 0; i< maxValue; i++)
for (int j = 0; j < maxValue; j++)
for (int k = 0; k < maxValue; k++)
if (i + j + k == maxValue && 2 * i + 4 * j + 6 * k == 1200)
result.Add(new Tuple<int, int, int>(i, j, k));
return result;
}
Thank you in advance.
Well, having
2x + 4y + 6z = 1200
x + y + z = 300
you can put it as
x + 2y + 3z = 600
x + y + z = 300
subtract 2nd from the 1st and you get
y + 2z = 300
or
y = 300 - 2z
Since x = 300 - y - z we can put it as
x = 300 - y - z =
= 300 - (300 - 2z) - z =
= 300 - 300 + 2z - z =
= z
Finally, for the arbitrary z (which is free variable)
x = z
y = 300 - 2 * z;
Possible c# code:
private static (int x, int y, int z) Solution(int x) => (x, 300 - 2 * x, x);
Demo:
string solutions = string.Join(Environment.NewLine, Enumerable
.Range(0, 10)
.Select(x => Solution(x)));
...
// 10 solutions for x = 0..9
string solutions = string.Join(Environment.NewLine, Enumerable
.Range(0, 10)
.Select(x => Solution(x)));
Console.Write(solutions);
Outcome:
(0, 300, 0)
(1, 298, 1)
(2, 296, 2)
(3, 294, 3)
(4, 292, 4)
(5, 290, 5)
(6, 288, 6)
(7, 286, 7)
(8, 284, 8)
(9, 282, 9)
If you are looking for non-negative solutions only (you've mentioned probabilities in the comments for the code), then use x in [0..150] range:
(0, 300, 0)
(1, 298, 1)
(2, 296, 2)
...
(148, 4, 148)
(149, 2, 149)
(150, 0, 150)
Edit: your Calculate() method improved:
public static List<Tuple<int, int, int>> Calculate() {
var result = new List<Tuple<int, int, int>>();
const int maxValue = 300;
int start = Math.Max(150 - maxValue / 2, 0);
for (int x = start; ; ++x) {
int y = 300 - 2 * x;
int z = x;
if (y < 0 || x > maxValue)
break;
result.Add(new Tuple<int, int, int>(x, y, z));
}
return result;
}
Math Theory
If you want a general method you should use some Linear Algebra theory.
Let's rewrite the equations in matrix form as A(x,y) + bz = c,
where:
A: is the matrix that contains the coefficents of the x,y coordinates
A = (2,4,1,1)
b = (6,1) (transposed) is the vector containing the z coefficents.
c = (1200, 300) (transposed) is the vector containing the constant terms.
then (x,y) = AInverse * (c - bz). That is a function of z (Let's say f(z)). So for every z you obtain a valid solution: (f(z),z). f(z) is a vector of 2 components.
Note
If A is not invertible because the equations (rstricted to x and y) are linearly dependent (i.e. the 2 equations are the "same" equation in x and y), this method fails.
Code
We can code that like that:
Step1
We must code the Matrix2x2. I do it from scratch now, but you maybe want to use some framework if you really need in production:
public record struct Matrix2x2 (float A00, float A01, float A10, float A11)
{
public float Determinant => A00 * A11 - A01 * A10;
public Matrix2x2 Invert() => Determinant != 0
? 1 / Determinant * new Matrix2x2() { A11 = A00, A00 = A11, A01 = -A01, A10 = -A10 }
: throw new InvalidOperationException($"Cannot Invert this matrix");
public static Matrix2x2 operator *(Matrix2x2 a, float number) => new()
{
A00 = a.A00 * number,
A01 = a.A01 * number,
A10 = a.A10 * number,
A11 = a.A11 * number,
};
public static Matrix2x2 operator *(float number, Matrix2x2 a) => a * number;
public static Vector2 operator *(Matrix2x2 a, Vector2 vector)
{
var x = a.A00 * vector.X + a.A01 * vector.Y;
var y = a.A10 * vector.X + a.A11 * vector.Y;
return new(x, y);
}
}
Step2
We must encode the equation. We need the Matrix A, the z coefficents and b, and the vector c of constant terms:
public delegate Vector3 SolutionSpace(float z);
public static class EquationHelper
{
public static SolutionSpace SolveEquation(Matrix2x2 equationMatrix, Vector2 b, Vector2 c) => z =>
{
var v = equationMatrix.Invert() * (c - z * b);
return new Vector3(v.X, v.Y, z);
};
}
Note: The object returned from this function is the solution space, that depends from 1 parameter (the z value). So we could see it as a function that maps (float z) => (x(z), y(z), z) that in c# is a delegate that returns a Vector3 and takes in input a float.
Usage
var A = new Matrix2x2(2, 4, 1, 1);
var b = new Vector2(6, 1);
var c = new Vector2(1200, 300);
var solution = EquationHelper.SolveEquation(A, b, c);
foreach(var z in Enumerable.Range(-10, 21))
Console.WriteLine(solution(z));
Output
Related
Lets N be a number (10<=N<=10^5).
I have to break it into 3 numbers (x,y,z) such that it validates the following conditions.
1. x<=y<=z
2. x^2+y^2=z^2-1;
3. x+y+z<=N
I have to find how many combinations I can get from the given numbers in a method.
I have tried as follows but it's taking so much time for a higher number and resulting in a timeout..
int N= Int32.Parse(Console.ReadLine());
List<String> res = new List<string>();
//x<=y<=z
int mxSqrt = N - 2;
int a = 0, b = 0;
for (int z = 1; z <= mxSqrt; z++)
{
a = z * z;
for (int y = 1; y <= z; y++)
{
b = y * y;
for (int x = 1; x <= y; x++)
{
int x1 = b + x * x;
int y1 = a - 1;
if (x1 == y1 && ((x + y + z) <= N))
{
res.Add(x + "," + y + "," + z);
}
}
}
}
Console.WriteLine(res.Count());
My question:
My solution is taking time for a bigger number (I think it's the
for loops), how can I improve it?
Is there any better approach for the same?
Here's a method that enumerates the triples, rather than exhaustively testing for them, using number theory as described here: https://mathoverflow.net/questions/29644/enumerating-ways-to-decompose-an-integer-into-the-sum-of-two-squares
Since the math took me a while to comprehend and a while to implement (gathering some code that's credited above it), and since I don't feel much of an authority on the subject, I'll leave it for the reader to research. This is based on expressing numbers as Gaussian integer conjugates. (a + bi)*(a - bi) = a^2 + b^2. We first factor the number, z^2 - 1, into primes, decompose the primes into Gaussian conjugates and find different expressions that we expand and simplify to get a + bi, which can be then raised, a^2 + b^2.
A perk of reading about the Sum of Squares Function is discovering that we can rule out any candidate z^2 - 1 that contains a prime of form 4k + 3 with an odd power. Using that check alone, I was able to reduce Prune's loop on 10^5 from 214 seconds to 19 seconds (on repl.it) using the Rosetta prime factoring code below.
The implementation here is just a demonstration. It does not have handling or optimisation for limiting x and y. Rather, it just enumerates as it goes. Play with it here.
Python code:
# https://math.stackexchange.com/questions/5877/efficiently-finding-two-squares-which-sum-to-a-prime
def mods(a, n):
if n <= 0:
return "negative modulus"
a = a % n
if (2 * a > n):
a -= n
return a
def powmods(a, r, n):
out = 1
while r > 0:
if (r % 2) == 1:
r -= 1
out = mods(out * a, n)
r /= 2
a = mods(a * a, n)
return out
def quos(a, n):
if n <= 0:
return "negative modulus"
return (a - mods(a, n))/n
def grem(w, z):
# remainder in Gaussian integers when dividing w by z
(w0, w1) = w
(z0, z1) = z
n = z0 * z0 + z1 * z1
if n == 0:
return "division by zero"
u0 = quos(w0 * z0 + w1 * z1, n)
u1 = quos(w1 * z0 - w0 * z1, n)
return(w0 - z0 * u0 + z1 * u1,
w1 - z0 * u1 - z1 * u0)
def ggcd(w, z):
while z != (0,0):
w, z = z, grem(w, z)
return w
def root4(p):
# 4th root of 1 modulo p
if p <= 1:
return "too small"
if (p % 4) != 1:
return "not congruent to 1"
k = p/4
j = 2
while True:
a = powmods(j, k, p)
b = mods(a * a, p)
if b == -1:
return a
if b != 1:
return "not prime"
j += 1
def sq2(p):
if p % 4 != 1:
return "not congruent to 1 modulo 4"
a = root4(p)
return ggcd((p,0),(a,1))
# https://rosettacode.org/wiki/Prime_decomposition#Python:_Using_floating_point
from math import floor, sqrt
def fac(n):
step = lambda x: 1 + (x<<2) - ((x>>1)<<1)
maxq = long(floor(sqrt(n)))
d = 1
q = n % 2 == 0 and 2 or 3
while q <= maxq and n % q != 0:
q = step(d)
d += 1
return q <= maxq and [q] + fac(n//q) or [n]
# My code...
# An answer for https://stackoverflow.com/questions/54110614/
from collections import Counter
from itertools import product
from sympy import I, expand, Add
def valid(ps):
for (p, e) in ps.items():
if (p % 4 == 3) and (e & 1):
return False
return True
def get_sq2(p, e):
if p == 2:
if e & 1:
return [2**(e / 2), 2**(e / 2)]
else:
return [2**(e / 2), 0]
elif p % 4 == 3:
return [p, 0]
else:
a,b = sq2(p)
return [abs(a), abs(b)]
def get_terms(cs, e):
if e == 1:
return [Add(cs[0], cs[1] * I)]
res = [Add(cs[0], cs[1] * I)**e]
for t in xrange(1, e / 2 + 1):
res.append(
Add(cs[0] + cs[1]*I)**(e-t) * Add(cs[0] - cs[1]*I)**t)
return res
def get_lists(ps):
items = ps.items()
lists = []
for (p, e) in items:
if p == 2:
a,b = get_sq2(2, e)
lists.append([Add(a, b*I)])
elif p % 4 == 3:
a,b = get_sq2(p, e)
lists.append([Add(a, b*I)**(e / 2)])
else:
lists.append(get_terms(get_sq2(p, e), e))
return lists
def f(n):
for z in xrange(2, n / 2):
zz = (z + 1) * (z - 1)
ps = Counter(fac(zz))
is_valid = valid(ps)
if is_valid:
print "valid (does not contain a prime of form\n4k + 3 with an odd power)"
print "z: %s, primes: %s" % (z, dict(ps))
lists = get_lists(ps)
cartesian = product(*lists)
for element in cartesian:
print "prime square decomposition: %s" % list(element)
p = 1
for item in element:
p *= item
print "complex conjugates: %s" % p
vals = p.expand(complex=True, evaluate=True).as_coefficients_dict().values()
x, y = vals[0], vals[1] if len(vals) > 1 else 0
print "x, y, z: %s, %s, %s" % (x, y, z)
print "x^2 + y^2, z^2-1: %s, %s" % (x**2 + y**2, z**2 - 1)
print ''
if __name__ == "__main__":
print f(100)
Output:
valid (does not contain a prime of form
4k + 3 with an odd power)
z: 3, primes: {2: 3}
prime square decomposition: [2 + 2*I]
complex conjugates: 2 + 2*I
x, y, z: 2, 2, 3
x^2 + y^2, z^2-1: 8, 8
valid (does not contain a prime of form
4k + 3 with an odd power)
z: 9, primes: {2: 4, 5: 1}
prime square decomposition: [4, 2 + I]
complex conjugates: 8 + 4*I
x, y, z: 8, 4, 9
x^2 + y^2, z^2-1: 80, 80
valid (does not contain a prime of form
4k + 3 with an odd power)
z: 17, primes: {2: 5, 3: 2}
prime square decomposition: [4 + 4*I, 3]
complex conjugates: 12 + 12*I
x, y, z: 12, 12, 17
x^2 + y^2, z^2-1: 288, 288
valid (does not contain a prime of form
4k + 3 with an odd power)
z: 19, primes: {2: 3, 3: 2, 5: 1}
prime square decomposition: [2 + 2*I, 3, 2 + I]
complex conjugates: (2 + I)*(6 + 6*I)
x, y, z: 6, 18, 19
x^2 + y^2, z^2-1: 360, 360
valid (does not contain a prime of form
4k + 3 with an odd power)
z: 33, primes: {17: 1, 2: 6}
prime square decomposition: [4 + I, 8]
complex conjugates: 32 + 8*I
x, y, z: 32, 8, 33
x^2 + y^2, z^2-1: 1088, 1088
valid (does not contain a prime of form
4k + 3 with an odd power)
z: 35, primes: {17: 1, 2: 3, 3: 2}
prime square decomposition: [4 + I, 2 + 2*I, 3]
complex conjugates: 3*(2 + 2*I)*(4 + I)
x, y, z: 18, 30, 35
x^2 + y^2, z^2-1: 1224, 1224
Here is a simple improvement in Python (converting to the faster equivalent in C-based code is left as an exercise for the reader). To get accurate timing for the computation, I removed printing the solutions themselves (after validating them in a previous run).
Use an outer loop for one free variable (I chose z), constrained only by its relation to N.
Use an inner loop (I chose y) constrained by the outer loop index.
The third variable is directly computed per requirement 2.
Timing results:
-------------------- 10
1 solutions found in 2.3365020751953125e-05 sec.
-------------------- 100
6 solutions found in 0.00040078163146972656 sec.
-------------------- 1000
55 solutions found in 0.030081748962402344 sec.
-------------------- 10000
543 solutions found in 2.2078349590301514 sec.
-------------------- 100000
5512 solutions found in 214.93411707878113 sec.
That's 3:35 for the large case, plus your time to collate and/or print the results.
If you need faster code (this is still pretty brute-force), look into Diophantine equations and parameterizations to generate (y, x) pairs, given the target value of z^2 - 1.
import math
import time
def break3(N):
"""
10 <= N <= 10^5
return x, y, z triples such that:
x <= y <= z
x^2 + y^2 = z^2 - 1
x + y + z <= N
"""
"""
Observations:
z <= x + y
z < N/2
"""
count = 0
z_limit = N // 2
for z in range(3, z_limit):
# Since y >= x, there's a lower bound on y
target = z*z - 1
ymin = int(math.sqrt(target/2))
for y in range(ymin, z):
# Given y and z, compute x.
# That's a solution iff x is integer.
x_target = target - y*y
x = int(math.sqrt(x_target))
if x*x == x_target and x+y+z <= N:
# print("solution", x, y, z)
count += 1
return count
test = [10, 100, 1000, 10**4, 10**5]
border = "-"*20
for case in test:
print(border, case)
start = time.time()
print(break3(case), "solutions found in", time.time() - start, "sec.")
The bounds of x and y are an important part of the problem. I personally went with this Wolfram Alpha query and checked the exact forms of the variables.
Thanks to #Bleep-Bloop and comments, a very elegant bound optimization was found, which is x < n and x <= y < n - x. The results are the same and the times are nearly identical.
Also, since the only possible values for x and y are positive even integers, we can reduce the amount of loop iterations by half.
To optimize even further, since we compute the upper bound of x, we build a list of all possible values for x and make the computation parallel. That saves a massive amount of time on higher values of N but it's a bit slower for smaller values because of the overhead of the parallelization.
Here's the final code:
Non-parallel version, with int values:
List<string> res = new List<string>();
int n2 = n * n;
double maxX = 0.5 * (2.0 * n - Math.Sqrt(2) * Math.Sqrt(n2 + 1));
for (int x = 2; x < maxX; x += 2)
{
int maxY = (int)Math.Floor((n2 - 2.0 * n * x - 1.0) / (2.0 * n - 2.0 * x));
for (int y = x; y <= maxY; y += 2)
{
int z2 = x * x + y * y + 1;
int z = (int)Math.Sqrt(z2);
if (z * z == z2 && x + y + z <= n)
res.Add(x + "," + y + "," + z);
}
}
Parallel version, with long values:
using System.Linq;
...
// Use ConcurrentBag for thread safety
ConcurrentBag<string> res = new ConcurrentBag<string>();
long n2 = n * n;
double maxX = 0.5 * (2.0 * n - Math.Sqrt(2) * Math.Sqrt(n2 + 1L));
// Build list to parallelize
int nbX = Convert.ToInt32(maxX);
List<int> xList = new List<int>();
for (int x = 2; x < maxX; x += 2)
xList.Add(x);
Parallel.ForEach(xList, x =>
{
int maxY = (int)Math.Floor((n2 - 2.0 * n * x - 1.0) / (2.0 * n - 2.0 * x));
for (long y = x; y <= maxY; y += 2)
{
long z2 = x * x + y * y + 1L;
long z = (long)Math.Sqrt(z2);
if (z * z == z2 && x + y + z <= n)
res.Add(x + "," + y + "," + z);
}
});
When ran individually on a i5-8400 CPU, I get these results:
N: 10; Solutions: 1;
Time elapsed: 0.03 ms (Not parallel, int)
N: 100; Solutions: 6;
Time elapsed: 0.05 ms (Not parallel, int)
N: 1000; Solutions: 55;
Time elapsed: 0.3 ms (Not parallel, int)
N: 10000; Solutions: 543;
Time elapsed: 13.1 ms (Not parallel, int)
N: 100000; Solutions: 5512;
Time elapsed: 849.4 ms (Parallel, long)
You must use long when N is greater than 36340, because when it's squared, it overflows an int's max value. Finally, the parallel version starts to get better than the simple one when N is around 23000, with ints.
No time to properly test it, but seemed to yield the same results as your code (at 100 -> 6 results and at 1000 -> 55 results).
With N=1000 a time of 2ms vs your 144ms also without List
and N=10000 a time of 28ms
var N = 1000;
var c = 0;
for (int x = 2; x < N; x+=2)
{
for (int y = x; y < (N - x); y+=2)
{
long z2 = x * x + y * y + 1;
int z = (int) Math.Sqrt(z2);
if (x + y + z > N)
break;
if (z * z == z2)
c++;
}
}
Console.WriteLine(c);
#include<iostream>
#include<math.h>
int main()
{
int N = 10000;
int c = 0;
for (int x = 2; x < N; x+=2)
{
for (int y = x; y < (N - x); y+=2)
{
auto z = sqrt(x * x + y * y + 1);
if(x+y+z>N){
break;
}
if (z - (int) z == 0)
{
c++;
}
}
}
std::cout<<c;
}
This is my solution. On testing the previous solutions for this problem I found that x,y are always even and z is odd. I dont know the mathematical nature behind this, I am currently trying to figure that out.
I want to get it done in C# and it should be covering all the test
cases based on condition provided in the question.
The basic code, converted to long to process the N <= 100000 upper limit, with every optimizaion thrown in I could. I used alternate forms from #Mat's (+1) Wolfram Alpha query to precompute as much as possible. I also did a minimal perfect square test to avoid millions of sqrt() calls at the upper limit:
public static void Main()
{
int c = 0;
long N = long.Parse(Console.ReadLine());
long N_squared = N * N;
double half_N_squared = N_squared / 2.0 - 0.5;
double x_limit = N - Math.Sqrt(2) / 2.0 * Math.Sqrt(N_squared + 1);
for (long x = 2; x < x_limit; x += 2)
{
long x_squared = x * x + 1;
double y_limit = (half_N_squared - N * x) / (N - x);
for (long y = x; y < y_limit; y += 2)
{
long z_squared = x_squared + y * y;
int digit = (int) z_squared % 10;
if (digit == 3 || digit == 7)
{
continue; // minimalist non-perfect square elimination
}
long z = (long) Math.Sqrt(z_squared);
if (z * z == z_squared)
{
c++;
}
}
}
Console.WriteLine(c);
}
I followed the trend and left out "the degenerate solution" as implied by the OP's code but not explicitly stated.
I have 3 very large signed integers.
long x = long.MaxValue;
long y = long.MaxValue - 1;
long z = long.MaxValue - 2;
I want to calculate their truncated average. Expected average value is long.MaxValue - 1, which is 9223372036854775806.
It is impossible to calculate it as:
long avg = (x + y + z) / 3; // 3074457345618258600
Note: I read all those questions about average of 2 numbers, but I don't see how that technique can be applied to average of 3 numbers.
It would be very easy with the usage of BigInteger, but let's assume I cannot use it.
BigInteger bx = new BigInteger(x);
BigInteger by = new BigInteger(y);
BigInteger bz = new BigInteger(z);
BigInteger bavg = (bx + by + bz) / 3; // 9223372036854775806
If I convert to double, then, of course, I lose precision:
double dx = x;
double dy = y;
double dz = z;
double davg = (dx + dy + dz) / 3; // 9223372036854780000
If I convert to decimal, it works, but also let's assume that I cannot use it.
decimal mx = x;
decimal my = y;
decimal mz = z;
decimal mavg = (mx + my + mz) / 3; // 9223372036854775806
Question: Is there a way to calculate the truncated average of 3 very large integers only with the usage of long type? Don't consider that question as C#-specific, just it is easier for me to provide samples in C#.
This code will work, but isn't that pretty.
It first divides all three values (it floors the values, so you 'lose' the remainder), and then divides the remainder:
long n = x / 3
+ y / 3
+ z / 3
+ ( x % 3
+ y % 3
+ z % 3
) / 3
Note that the above sample does not always work properly when having one or more negative values.
As discussed with Ulugbek, since the number of comments are exploding below, here is the current BEST solution for both positive and negative values.
Thanks to answers and comments of Ulugbek Umirov, James S, KevinZ, Marc van Leeuwen, gnasher729 this is the current solution:
static long CalculateAverage(long x, long y, long z)
{
return (x % 3 + y % 3 + z % 3 + 6) / 3 - 2
+ x / 3 + y / 3 + z / 3;
}
static long CalculateAverage(params long[] arr)
{
int count = arr.Length;
return (arr.Sum(n => n % count) + count * (count - 1)) / count - (count - 1)
+ arr.Sum(n => n / count);
}
NB - Patrick has already given a great answer. Expanding on this you could do a generic version for any number of integers like so:
long x = long.MaxValue;
long y = long.MaxValue - 1;
long z = long.MaxValue - 2;
long[] arr = { x, y, z };
var avg = arr.Select(i => i / arr.Length).Sum()
+ arr.Select(i => i % arr.Length).Sum() / arr.Length;
Patrick Hofman has posted a great solution. But if needed it can still be implemented in several other ways. Using the algorithm here I have another solution. If implemented carefully it may be faster than the multiple divisions in systems with slow hardware divisors. It can be further optimized by using divide by constants technique from hacker's delight
public class int128_t {
private int H;
private long L;
public int128_t(int h, long l)
{
H = h;
L = l;
}
public int128_t add(int128_t a)
{
int128_t s;
s.L = L + a.L;
s.H = H + a.H + (s.L < a.L);
return b;
}
private int128_t rshift2() // right shift 2
{
int128_t r;
r.H = H >> 2;
r.L = (L >> 2) | ((H & 0x03) << 62);
return r;
}
public int128_t divideby3()
{
int128_t sum = {0, 0}, num = new int128_t(H, L);
while (num.H || num.L > 3)
{
int128_t n_sar2 = num.rshift2();
sum = add(n_sar2, sum);
num = add(n_sar2, new int128_t(0, num.L & 3));
}
if (num.H == 0 && num.L == 3)
{
// sum = add(sum, 1);
sum.L++;
if (sum.L == 0) sum.H++;
}
return sum;
}
};
int128_t t = new int128_t(0, x);
t = t.add(new int128_t(0, y));
t = t.add(new int128_t(0, z));
t = t.divideby3();
long average = t.L;
In C/C++ on 64-bit platforms it's much easier with __int128
int64_t average = ((__int128)x + y + z)/3;
You can calculate the mean of numbers based on the differences between the numbers rather than using the sum.
Let's say x is the max, y is the median, z is the min (as you have). We will call them max, median and min.
Conditional checker added as per #UlugbekUmirov's comment:
long tmp = median + ((min - median) / 2); //Average of min 2 values
if (median > 0) tmp = median + ((max - median) / 2); //Average of max 2 values
long mean;
if (min > 0) {
mean = min + ((tmp - min) * (2.0 / 3)); //Average of all 3 values
} else if (median > 0) {
mean = min;
while (mean != tmp) {
mean += 2;
tmp--;
}
} else if (max > 0) {
mean = max;
while (mean != tmp) {
mean--;
tmp += 2;
}
} else {
mean = max + ((tmp - max) * (2.0 / 3));
}
Patching Patrick Hofman's solution with supercat's correction, I give you the following:
static Int64 Avg3 ( Int64 x, Int64 y, Int64 z )
{
UInt64 flag = 1ul << 63;
UInt64 x_ = flag ^ (UInt64) x;
UInt64 y_ = flag ^ (UInt64) y;
UInt64 z_ = flag ^ (UInt64) z;
UInt64 quotient = x_ / 3ul + y_ / 3ul + z_ / 3ul
+ ( x_ % 3ul + y_ % 3ul + z_ % 3ul ) / 3ul;
return (Int64) (quotient ^ flag);
}
And the N element case:
static Int64 AvgN ( params Int64 [ ] args )
{
UInt64 length = (UInt64) args.Length;
UInt64 flag = 1ul << 63;
UInt64 quotient_sum = 0;
UInt64 remainder_sum = 0;
foreach ( Int64 item in args )
{
UInt64 uitem = flag ^ (UInt64) item;
quotient_sum += uitem / length;
remainder_sum += uitem % length;
}
return (Int64) ( flag ^ ( quotient_sum + remainder_sum / length ) );
}
This always gives the floor() of the mean, and eliminates every possible edge case.
Because C uses floored division rather than Euclidian division, it may easier to compute a properly-rounded average of three unsigned values than three signed ones. Simply add 0x8000000000000000UL to each number before taking the unsigned average, subtract it after taking the result, and use an unchecked cast back to Int64 to get a signed average.
To compute the unsigned average, compute the sum of the top 32 bits of the three values. Then compute the sum of the bottom 32 bits of the three values, plus the sum from above, plus one [the plus one is to yield a rounded result]. The average will be 0x55555555 times the first sum, plus one third of the second.
Performance on 32-bit processors might be enhanced by producing three "sum" values each of which is 32 bits long, so that the final result is ((0x55555555UL * sumX)<<32) + 0x55555555UL * sumH + sumL/3; it might possibly be further enhanced by replacing sumL/3 with ((sumL * 0x55555556UL) >> 32), though the latter would depend upon the JIT optimizer [it might know how to replace a division by 3 with a multiply, and its code might actually be more efficient than an explicit multiply operation].
If you know you have N values, can you just divide each value by N and sum them together?
long GetAverage(long* arrayVals, int n)
{
long avg = 0;
long rem = 0;
for(int i=0; i<n; ++i)
{
avg += arrayVals[i] / n;
rem += arrayVals[i] % n;
}
return avg + (rem / n);
}
You could use the fact that you can write each of the numbers as y = ax + b, where x is a constant. Each a would be y / x (the integer part of that division). Each b would be y % x (the rest/modulo of that division). If you choose this constant in an intelligent way, for example by choosing the square root of the maximum number as a constant, you can get the average of x numbers without having problems with overflow.
The average of an arbitrary list of numbers can be found by finding:
( ( sum( all A's ) / length ) * constant ) +
( ( sum( all A's ) % length ) * constant / length) +
( ( sum( all B's ) / length )
where % denotes modulo and / denotes the 'whole' part of division.
The program would look something like:
class Program
{
static void Main()
{
List<long> list = new List<long>();
list.Add( long.MaxValue );
list.Add( long.MaxValue - 1 );
list.Add( long.MaxValue - 2 );
long sumA = 0, sumB = 0;
long res1, res2, res3;
//You should calculate the following dynamically
long constant = 1753413056;
foreach (long num in list)
{
sumA += num / constant;
sumB += num % constant;
}
res1 = (sumA / list.Count) * constant;
res2 = ((sumA % list.Count) * constant) / list.Count;
res3 = sumB / list.Count;
Console.WriteLine( res1 + res2 + res3 );
}
}
I also tried it and come up with a faster solution (although only by a factor about 3/4). It uses a single division
public static long avg(long a, long b, long c) {
final long quarterSum = (a>>2) + (b>>2) + (c>>2);
final long lowSum = (a&3) + (b&3) + (c&3);
final long twelfth = quarterSum / 3;
final long quarterRemainder = quarterSum - 3*twelfth;
final long adjustment = smallDiv3(lowSum + 4*quarterRemainder);
return 4*twelfth + adjustment;
}
where smallDiv3 is division by 3 using multipliation and working only for small arguments
private static long smallDiv3(long n) {
assert -30 <= n && n <= 30;
// Constants found rather experimentally.
return (64/3*n + 10) >> 6;
}
Here is the whole code including a test and a benchmark, the results are not that impressive.
This function computes the result in two divisions. It should generalize nicely to other divisors and word sizes.
It works by computing the double-word addition result, then working out the division.
Int64 average(Int64 a, Int64 b, Int64 c) {
// constants: 0x10000000000000000 div/mod 3
const Int64 hdiv3 = UInt64(-3) / 3 + 1;
const Int64 hmod3 = UInt64(-3) % 3;
// compute the signed double-word addition result in hi:lo
UInt64 lo = a; Int64 hi = a>=0 ? 0 : -1;
lo += b; hi += b>=0 ? lo<b : -(lo>=UInt64(b));
lo += c; hi += c>=0 ? lo<c : -(lo>=UInt64(c));
// divide, do a correction when high/low modulos add up
return hi>=0 ? lo/3 + hi*hdiv3 + (lo%3 + hi*hmod3)/3
: lo/3+1 + hi*hdiv3 + Int64(lo%3-3 + hi*hmod3)/3;
}
Math
(x + y + z) / 3 = x/3 + y/3 + z/3
(a[1] + a[2] + .. + a[k]) / k = a[1]/k + a[2]/k + .. + a[k]/k
Code
long calculateAverage (long a [])
{
double average = 0;
foreach (long x in a)
average += (Convert.ToDouble(x)/Convert.ToDouble(a.Length));
return Convert.ToInt64(Math.Round(average));
}
long calculateAverage_Safe (long a [])
{
double average = 0;
double b = 0;
foreach (long x in a)
{
b = (Convert.ToDouble(x)/Convert.ToDouble(a.Length));
if (b >= (Convert.ToDouble(long.MaxValue)-average))
throw new OverflowException ();
average += b;
}
return Convert.ToInt64(Math.Round(average));
}
Try this:
long n = Array.ConvertAll(new[]{x,y,z},v=>v/3).Sum()
+ (Array.ConvertAll(new[]{x,y,z},v=>v%3).Sum() / 3);
How do you solve this type of equation?
a *X + b * Y + c *Z = q
d *X + e * Y + f *Z = w
X *X + Y * Y + Z *Z = z
We are looking for X,Y,Z. If not the squares in the last row this could be solved as a typical linear equation, for example using Linear Equations from Dot Numerics, or writing Gauss Elimination.
But how do I solve this one? Also, do you know any libraries in .NET that solves that equation?
This may be viewed as a set of equations for 2 planes and a sphere. The solution finds the intersection of the 2 planes (a line) and then the intersection of that line with the sphere.
There may be 0, 1, or 2 unique solutions.
The code is C, but I assume OP can readily translate to c#
// Eq1: a *X + b * Y + c *Z = q
// Eq2: d *X + e * Y + f *Z = w
// Eq3: X *X + Y * Y + Z *Z = z
typedef struct {
double x,y,z,s;
} plane_t;
typedef struct {
double x,y,z;
} point_t;
int Interection_PlanePlaneSphere(point_t XYZ[2], const plane_t *abc, const plane_t *def, double radius) {
// Find intersection of 2 planes
// V = abc cross def
point_t V; // This is really 3D vector, not a point
V.x = abc->y*def->z - abc->z*def->y;
V.y = abc->z*def->x - abc->x*def->z;
V.z = abc->x*def->y - abc->y*def->x;
// printf("V (%12g, %12g, %12g)\n", V.x, V.y, V.z);
// Assume both planes go through z plane, e.g. z = 0 and V.z != 0
// Code could be adapted to not depend on this assumption.
// abc->x*P.x + abc->y*P.y = abc->s
// def->x*P.x + def->y*P.y = def->s
double det = abc->x*def->y - abc->y*def->x;
// if Planes are parallel ...
// Code could be adapted to deal with special case where planes are coincident.
if (det == 0.0) return 0; //
point_t P;
P.x = ( abc->s*def->y - def->s*abc->y)/det;
P.y = (-abc->s*def->x + def->s*abc->x)/det;
P.z = 0.0;
// L(t) = P + V*t = intersection of the 2 planes
// printf("p (%12g, %12g, %12g)\n", P.x, P.y, P.z);
if (radius < 0) return 0; // bad sphere
// Find where L(t) is on the sphere, or |L(t)| = radius^2
// (P.x - V.x*t)^2 + (P.y - V.y*t)^2 + (P.z - V.z*t)^2 = radius^2
// (V.x^2 + V.y^2 + V.z^2)*t^2 - 2*(P.x*V.x + P.y*V.y + P.z*V.z) + (P.x^2 + P.y^2 + P.z^2) = radius^2;
// Solve quadratic
double a, b, c;
a = V.x*V.x + V.y*V.y + V.z*V.z;
b = -2*(P.x*V.x + P.y*V.y + P.z*V.z);
c = P.x*P.x + P.y*P.y + P.z*P.z - radius*radius;
// printf("abc (%12g, %12g, %12g)\n", a, b, c);
det = b*b - 4*a*c;
if (det < 0) return 0; // no solutions
det = sqrt(det);
double t;
t = (-b + det)/(2*a);
XYZ[0].x = P.x + t*V.x;
XYZ[0].y = P.y + t*V.y;
XYZ[0].z = P.z + t*V.z;
if (det == 0.0) return 1;
t = (-b - det)/(2*a);
XYZ[1].x = P.x + t*V.x;
XYZ[1].y = P.y + t*V.y;
XYZ[1].z = P.z + t*V.z;
return 2;
}
void Test() {
plane_t abcq = {2, -1, 1, 5};
plane_t defw = {1, 1, -1, 1};
double z = 100;
point_t XYZ[2];
int result = Interection_PlanePlaneSphere(XYZ, &abcq, &defw, sqrt(z));
printf("Result %d\n", result);
int i=0;
for (i=0; i<result; i++) {
printf("XYZ[%d] (%12g, %12g, %12g)\n", i, XYZ[i].x, XYZ[i].y, XYZ[i].z);
}
// Result 2
// XYZ[0] ( 2, 5.41014, 6.41014)
// XYZ[1] ( 2, -8.41014, -7.41014)
}
I am doing image manipulation and I want to rotate all of the pixels in xyz space based on an angle, the origin, and an x,y, and z coordinate.
I just need to setup the proper matrix (4x4) and then I will be good from there. The Angle is in degrees, not radians and the x,y,z are all going to be from -1 to 1 (floats)
EDIT:
Ok, here is the code that I whipped up to do the rotation about a given line defined by the origin and an X, Y, Z coorinate.
float ang = angD * (float)(Math.PI / 180); // from degrees to radians, if needed
//U = n*n(t) + cos(a)*(I-n*n(t)) + sin(a)*N(x).
var u = MatrixDouble.Identity(4); // 4x4 Identity Matrix
u = u.Multiply(Math.Cos(ang));
var n = new MatrixDouble(1, 4, new List<double> { x, y, z, 0 });
var nt = n.Transpose();
// This next part is the N(x) matrix. The data is inputted in Column
// first order and fills in the 4x4 matrix with the given 16 Doubles
var nx = new MatrixDouble(4, 4, new List<double> { 0, z, -y, 0, -z, 0, x, 0, y, -x, 0, 0, 0, 0, 0, 1 });
nx = nx.Multiply(Math.Sin(ang));
var ret = nt.Multiply(n);
ret[3, 3] = 1;
u = u.Subtract(ret);
u = ret.Add(u.Add(nx));
It's a little complicated and I'm using a custom Matrix library, but nothing up there should be too hard to implement with any functioning Matrix lib.
Phew, lots of math!
The complete rotation matrices are derived and given at https://sites.google.com/site/glennmurray/glenn-murray-ph-d/rotation-matrices-and-formulas/rotation-about-an-arbitrary-axis-in-3-dimensions.
From the paper:
5.2 The simplified matrix for rotations about the origin
Note this assumes that (u, v, w) is a direction vector for the axis of rotation and that u^2 + v^2 + w^2 = 1.
If you have a point (x, y, z) that you want to rotate, then we can obtain a function of of seven variables that yields the rotated point:
f(x, y, z, u, v, w, theta) =
The paper also includes matrices and formulas for rotations about an arbitrary axis (not necessarily through the origin), Java code available under the Apache license, and a link to a web app that illustrates rotations.
Use the Matrix3D Structure (MSDN) - Represents a 4 x 4 matrix used for transformations in 3-D space
Take a look here for a tutorial: Building a 3D Engine
Essentially, matrices are built for X, Y, and Z rotations and then you can multiply the rotations in any order.
public static Matrix3D NewRotateAroundX(double radians)
{
var matrix = new Matrix3D();
matrix._matrix[1, 1] = Math.Cos(radians);
matrix._matrix[1, 2] = Math.Sin(radians);
matrix._matrix[2, 1] = -(Math.Sin(radians));
matrix._matrix[2, 2] = Math.Cos(radians);
return matrix;
}
public static Matrix3D NewRotateAroundY(double radians)
{
var matrix = new Matrix3D();
matrix._matrix[0, 0] = Math.Cos(radians);
matrix._matrix[0, 2] = -(Math.Sin(radians));
matrix._matrix[2, 0] = Math.Sin(radians);
matrix._matrix[2, 2] = Math.Cos(radians);
return matrix;
}
public static Matrix3D NewRotateAroundZ(double radians)
{
var matrix = new Matrix3D();
matrix._matrix[0, 0] = Math.Cos(radians);
matrix._matrix[0, 1] = Math.Sin(radians);
matrix._matrix[1, 0] = -(Math.Sin(radians));
matrix._matrix[1, 1] = Math.Cos(radians);
return matrix;
}
Function rotateAroundAxis() rotates point around any axis in 3D. It is my solution to the rotation in 3D using analytic geometry and programming to model the process. The code is in JavaScript.
function rotateAroundAxis(A, B, C, alpha, precision) {
// A is rotated point, BC is axis, alpha is angle
// A, B, C are points in format [Ax, Ay, Az], alpha is float, precision is int
// A2 is output in format [A2x, A2y, A2z]
if((A[0] - B[0])*(A[1] - C[1]) == (A[1] - B[1])*(A[0] - C[0]) && (A[1] - B[1])*(A[2] - C[2]) == (A[1] - C[1])*(A[2] - B[2]) && (A[0] - B[0])*(A[2] - C[2]) == (A[0] - C[0])*(A[2] - B[2])) {
return A
}// Return the original point if it is on the axis.
var D = findClosestPoint(A, B, C, precision);
var w = crossProduct(new Array(C[0] - B[0], C[1] - B[1], C[2] - B[2]), new Array(C[0] - A[0], C[1] - A[1], C[2] - A[2]));
var W = pointPlusVector(A, w);
var sizeAW = vectorSize(A, W);
var sizeDA = vectorSize(D, A);
var sizeAE = sizeDA*(Math.sin(0.5*alpha))/(Math.cos(0.5*alpha));
var E = new Array(A[0] + (W[0] - A[0])*sizeAE/sizeAW, A[1] + (W[1] - A[1])*sizeAE/sizeAW, A[2] + (W[2] - A[2])*sizeAE/sizeAW);
var sizeDE = vectorSize(D, E);
var sizeEF = sizeAE*Math.sin(alpha/2);
var F = new Array(D[0] + (E[0] - D[0])*(sizeDE - sizeEF)/sizeDE, D[1] + (E[1] - D[1])*(sizeDE - sizeEF)/sizeDE, D[2] + (E[2] - D[2])*(sizeDE - sizeEF)/sizeDE);
var A2 = new Array(A[0] + 2*(F[0] - A[0]), A[1] + 2*(F[1] - A[1]), A[2] + 2*(F[2] - A[2]))
return A2;
}
function angleSize(A, S, B) {
ux = A[0] - S[0]; uy = A[1] - S[1]; uz = A[2] - S[2];
vx = B[0] - S[0]; vy = B[1] - S[1]; vz = B[2] - S[2];
if((Math.sqrt(ux*ux + uy*uy + uz*uz)*Math.sqrt(vx*vx + vy*vy + vz*vz)) == 0) {return 0}
return Math.acos((ux*vx + uy*vy + uz*vz)/(Math.sqrt(ux*ux + uy*uy + uz*uz)*Math.sqrt(vx*vx + vy*vy + vz*vz)));
}
function findClosestPoint(N, B, C, precision) {
// We will devide the segment BC into many tiny segments and we will choose the point F where the |NB F| distance is the shortest.
if(B[0] == C[0] && B[1] == C[1] && B[2] == C[2]) {return B}
var shortest = 0;
for(var i = 0; i <= precision; i++) {
var Fx = Math.round(precision*precision*(B[0] + (C[0] - B[0])*i/precision))/(precision*precision);
var Fy = Math.round(precision*precision*(B[1] + (C[1] - B[1])*i/precision))/(precision*precision);
var Fz = Math.round(precision*precision*(B[2] + (C[2] - B[2])*i/precision))/(precision*precision);
var sizeF = vectorSize(new Array(N[0], N[1], N[2]), new Array(Fx, Fy, Fz));
if(i == 0 || sizeF < shortest) { // first run or condition
shortest = sizeF;
F = new Array(Fx, Fy, Fz);
}
}
// recursion, if it is an outer point return findClosestPoint(we mirror further point in the closer one)
if(F[0] == Math.round(precision*precision*(B[0]))/(precision*precision) && F[1] == Math.round(precision*precision*(B[1]))/(precision*precision) && F[2] == Math.round(precision*precision*(B[2]))/(precision*precision)) { // F == B
if(Math.round(precision*precision*180*angleSize(C, B, N)/Math.PI)/(precision*precision) <= 90){return F} else {return findClosestPoint(N, new Array(2*B[0] - C[0], 2*B[1] - C[1], 2*B[2] - C[2]), B, precision)}
} else if (F[0] == Math.round(precision*precision*(C[0]))/(precision*precision) && F[1] == Math.round(precision*precision*(C[1]))/(precision*precision) && F[2] == Math.round(precision*precision*(C[2]))/(precision*precision)) { // F == C
if(Math.round(precision*precision*180*angleSize(B, C, N)/Math.PI)/(precision*precision) <= 90) {return F} else {return findClosestPoint(N, C, new Array(2*C[0] - B[0], 2*C[1] - B[1], 2*C[2] - B[2]), precision)}
} else {return F;}
}
function vectorSize(A, B) {
var ux = A[0] - B[0];
var uy = A[1] - B[1];
var uz = A[2] - B[2];
return Math.sqrt(ux*ux + uy*uy + uz*uz);
}
function crossProduct(u, v) {
return (new Array(u[1]*v[2] - u[2]*v[1], u[2]*v[0] - u[0]*v[2], u[0]*v[1] - u[1]*v[0]));
}
function pointPlusVector (A, v) {
return (new Array(A[0] + v[0], A[1] + v[1], A[2] + v[2]));
}
Trying to find functions that will assist us to draw a 3D line through a series of points.
For each point we know: Date&Time, Latitude, Longitude, Altitude, Speed and Heading.
Data might be recorded every 10 seconds and we would like to be able to guestimate the points in between and increase granularity to 1 second. Thus creating a virtual flight path in 3D space.
I have found a number of curve fitting algorithms that will approximate a line through a series of points but they do not guarantee that the points are intersected. They also do not take into account speed and heading to determine the most likely path taken by the object to reach the next point.
From a physics viewpoint:
You have to assume something about the acceleration in your intermediate points to get the interpolation.
If your physical system is relatively well-behaved (as a car or a plane), as opposed to for example a bouncing ball, you may go ahead supposing an acceleration varying linearly with time between your points.
The vector equation for a constant varying accelerated movement is:
x''[t] = a t + b
where all magnitudes except t are vectors.
For each segment you already know v(t=t0) x(t=t0) tfinal and x(tfinal) v(tfinal)
By solving the differential equation you get:
Eq 1:
x[t_] := (3 b t^2 Tf + a t^3 Tf - 3 b t Tf^2 - a t Tf^3 - 6 t X0 + 6 Tf X0 + 6 t Xf)/(6 Tf)
And imposing the initial and final contraints for position and velocity you get:
Eqs 2:
a -> (6 (Tf^2 V0 - 2 T0 Tf Vf + Tf^2 Vf - 2 T0 X0 + 2 Tf X0 +
2 T0 Xf - 2 Tf Xf))/(Tf^2 (3 T0^2 - 4 T0 Tf + Tf^2))
b -> (2 (-2 Tf^3 V0 + 3 T0^2 Tf Vf - Tf^3 Vf + 3 T0^2 X0 -
3 Tf^2 X0 - 3 T0^2 Xf + 3 Tf^2 Xf))/(Tf^2 (3 T0^2 - 4 T0 Tf + Tf^2))}}
So inserting the values for eqs 2 into eq 1 you get the temporal interpolation for your points, based on the initial and final position and velocities.
HTH!
Edit
A few examples with abrupt velocity change in two dimensions (in 3D is exactly the same). If the initial and final speeds are similar, you'll get "straighter" paths.
Suppose:
X0 = {0, 0}; Xf = {1, 1};
T0 = 0; Tf = 1;
If
V0 = {0, 1}; Vf = {-1, 3};
V0 = {0, 1}; Vf = {-1, 5};
V0 = {0, 1}; Vf = {1, 3};
Here is an animation where you may see the speed changing from V0 = {0, 1} to Vf = {1, 5}:
Here you may see an accelerating body in 3D with positions taken at equal intervals:
Edit
A full problem:
For convenience, I'll work in Cartesian coordinates. If you want to convert from lat/log/alt to Cartesian just do:
x = rho sin(theta) cos(phi)
y = rho sin(theta) sin(phi)
z = rho cos(theta)
Where phi is the longitude, theta is the latitude, and rho is your altitude plus the radius of the Earth.
So suppose we start our segment at:
t=0 with coordinates (0,0,0) and velocity (1,0,0)
and end at
t=10 with coordinates (10,10,10) and velocity (0,0,1)
I clearly made a change in the origin of coordinates to set the origin at my start point. That is just for getting nice round numbers ...
So we replace those numbers in the formulas for a and b and get:
a = {-(3/50), -(3/25), -(3/50)} b = {1/5, 3/5, 2/5}
With those we go to eq 1, and the position of the object is given by:
p[t] = {1/60 (60 t + 6 t^2 - (3 t^3)/5),
1/60 (18 t^2 - (6 t^3)/5),
1/60 (12 t^2 - (3 t^3)/5)}
And that is it. You get the position from 1 to 10 secs replacing t by its valus in the equation above.
The animation runs:
Edit 2
If you don't want to mess with the vertical acceleration (perhaps because your "speedometer" doesn't read it), you could just assign a constant speed to the z axis (there is a very minor error for considering it parallel to the Rho axis), equal to (Zfinal - Zinit)/(Tf-T0), and then solve the problem in the plane forgetting the altitude.
What you're asking is a general interpolation problem. My guess is your actual problem isn't due to the curve-fitting algorithm being used, but rather your application of it to all discrete values recorded by the system instead of the relevant set of values.
Let's decompose your problem. You're currently drawing a point in spherically-mapped 3D space, adjusting for linear and curved paths. If we discretize the operations performed by an object with six degrees of freedom (roll, pitch, and yaw), the only operations you're particularly interested in are linear paths and curved paths accounting for pitch and yaw in any direction. Accounting for acceleration and deceleration also possible given understanding of basic physics.
Dealing with the spherical mapping is easy. Simply unwrap your points relative to their position on a plane, adjusting for latitude, longitude, and altitude. This should allow you to flatten data that would otherwise exist along a curved path, though this may not strictly be necessary for the solutions to your problem (see below).
Linear interpolation is easy. Given an arbitrary number of points backwards in time that fit a line within n error as determined by your system,* construct the line and compute the distance in time between each point. From here, attempt to fit the time points to one of two cases: constant velocity or constant acceleration.
Curve interpolation is a little more difficult, but still plausible. For cases of pitch, yaw, or combined pitch+yaw, construct a plane containing an arbitrary number of points backwards in time, within m error for curved readouts from your system.* From these data, construct a planar curve and once again account for constant velocity or acceleration along the curve.
You can do better than this by attempting to predict the expected operations of a plane in flight as part of a decision tree or neural network relative to the flight path. I'll leave that as an exercise for the reader.
Best of luck designing your system.
--
* Both error readouts are expected to be from GPS data, given the description of the problem. Accounting and adjusting for errors in these data is a separate interesting problem.
What you need (instead of modeling the physics) is to fit a spline through the data. I used a numerical recipies book (http://www.nrbook.com/a has free C and FORTRAN algorithms. Look into F77 section 3.3 to get the math needed). If you want to be simple then just fit lines through the points, but that will not result in a smooth flight path at all. Time will be your x value, and each parameter loged will have it's own cublic spline parameters.
Since we like long postings for this question here is the full code:
//driver program
static void Main(string[] args)
{
double[][] flight_data = new double[][] {
new double[] { 0, 10, 20, 30 }, // time in seconds
new double[] { 14500, 14750, 15000, 15125 }, //altitude in ft
new double[] { 440, 425, 415, 410 }, // speed in knots
};
CubicSpline altitude = new CubicSpline(flight_data[0], flight_data[1]);
CubicSpline speed = new CubicSpline(flight_data[0], flight_data[2]);
double t = 22; //Find values at t
double h = altitude.GetY(t);
double v = speed.GetY(t);
double ascent = altitude.GetYp(t); // ascent rate in ft/s
}
// Cubic spline definition
using System.Linq;
/// <summary>
/// Cubic spline interpolation for tabular data
/// </summary>
/// <remarks>
/// Adapted from numerical recipies for FORTRAN 77
/// (ISBN 0-521-43064-X), page 110, section 3.3.
/// Function spline(x,y,yp1,ypn,y2) converted to
/// C# by jalexiou, 27 November 2007.
/// Spline integration added also Nov 2007.
/// </remarks>
public class CubicSpline
{
double[] xi;
double[] yi;
double[] yp;
double[] ypp;
double[] yppp;
double[] iy;
#region Constructors
public CubicSpline(double x_min, double x_max, double[] y)
: this(Sequence(x_min, x_max, y.Length), y)
{ }
public CubicSpline(double x_min, double x_max, double[] y, double yp1, double ypn)
: this(Sequence(x_min, x_max, y.Length), y, yp1, ypn)
{ }
public CubicSpline(double[] x, double[] y)
: this(x, y, double.NaN, double.NaN)
{ }
public CubicSpline(double[] x, double[] y, double yp1, double ypn)
{
if( x.Length == y.Length )
{
int N = x.Length;
xi = new double[N];
yi = new double[N];
x.CopyTo(xi, 0);
y.CopyTo(yi, 0);
if( N > 0 )
{
double p, qn, sig, un;
ypp = new double[N];
double[] u = new double[N];
if( double.IsNaN(yp1) )
{
ypp[0] = 0;
u[0] = 0;
}
else
{
ypp[0] = -0.5;
u[0] = (3 / (xi[1] - xi[0])) *
((yi[1] - yi[0]) / (x[1] - x[0]) - yp1);
}
for (int i = 1; i < N-1; i++)
{
double hp = x[i] - x[i - 1];
double hn = x[i + 1] - x[i];
sig = hp / hn;
p = sig * ypp[i - 1] + 2.0;
ypp[i] = (sig - 1.0) / p;
u[i] = (6 * ((y[i + 1] - y[i]) / hn) - (y[i] - y[i - 1]) / hp)
/ (hp + hn) - sig * u[i - 1] / p;
}
if( double.IsNaN(ypn) )
{
qn = 0;
un = 0;
}
else
{
qn = 0.5;
un = (3 / (x[N - 1] - x[N - 2])) *
(ypn - (y[N - 1] - y[N - 2]) / (x[N - 1] - x[N - 2]));
}
ypp[N - 1] = (un - qn * u[N - 2]) / (qn * ypp[N - 2] + 1.0);
for (int k = N-2; k > 0; k--)
{
ypp[k] = ypp[k] * ypp[k + 1] + u[k];
}
// Calculate 1st derivatives
yp = new double[N];
double h;
for( int i = 0; i < N - 1; i++ )
{
h = xi[i + 1] - xi[i];
yp[i] = (yi[i + 1] - yi[i]) / h
- h / 6 * (ypp[i + 1] + 2 * ypp[i]);
}
h = xi[N - 1] - xi[N - 2];
yp[N - 1] = (yi[N - 1] - yi[N - 2]) / h
+ h / 6 * (2 * ypp[N - 1] + ypp[N - 2]);
// Calculate 3rd derivatives as average of dYpp/dx
yppp = new double[N];
double[] jerk_ij = new double[N - 1];
for( int i = 0; i < N - 1; i++ )
{
h = xi[i + 1] - xi[i];
jerk_ij[i] = (ypp[i + 1] - ypp[i]) / h;
}
Yppp = new double[N];
yppp[0] = jerk_ij[0];
for( int i = 1; i < N - 1; i++ )
{
yppp[i] = 0.5 * (jerk_ij[i - 1] + jerk_ij[i]);
}
yppp[N - 1] = jerk_ij[N - 2];
// Calculate Integral over areas
iy = new double[N];
yi[0] = 0; //Integration constant
for( int i = 0; i < N - 1; i++ )
{
h = xi[i + 1] - xi[i];
iy[i + 1] = h * (yi[i + 1] + yi[i]) / 2
- h * h * h / 24 * (ypp[i + 1] + ypp[i]);
}
}
else
{
yp = new double[0];
ypp = new double[0];
yppp = new double[0];
iy = new double[0];
}
}
else
throw new IndexOutOfRangeException();
}
#endregion
#region Actions/Functions
public int IndexOf(double x)
{
//Use bisection to find index
int i1 = -1;
int i2 = Xi.Length;
int im;
double x1 = Xi[0];
double xn = Xi[Xi.Length - 1];
bool ascending = (xn >= x1);
while( i2 - i1 > 1 )
{
im = (i1 + i2) / 2;
double xm = Xi[im];
if( ascending & (x >= Xi[im]) ) { i1 = im; } else { i2 = im; }
}
if( (ascending && (x <= x1)) || (!ascending & (x >= x1)) )
{
return 0;
}
else if( (ascending && (x >= xn)) || (!ascending && (x <= xn)) )
{
return Xi.Length - 1;
}
else
{
return i1;
}
}
public double GetIntY(double x)
{
int i = IndexOf(x);
double x1 = xi[i];
double x2 = xi[i + 1];
double y1 = yi[i];
double y2 = yi[i + 1];
double y1pp = ypp[i];
double y2pp = ypp[i + 1];
double h = x2 - x1;
double h2 = h * h;
double a = (x-x1)/h;
double a2 = a*a;
return h / 6 * (3 * a * (2 - a) * y1
+ 3 * a2 * y2 - a2 * h2 * (a2 - 4 * a + 4) / 4 * y1pp
+ a2 * h2 * (a2 - 2) / 4 * y2pp);
}
public double GetY(double x)
{
int i = IndexOf(x);
double x1 = xi[i];
double x2 = xi[i + 1];
double y1 = yi[i];
double y2 = yi[i + 1];
double y1pp = ypp[i];
double y2pp = ypp[i + 1];
double h = x2 - x1;
double h2 = h * h;
double A = 1 - (x - x1) / (x2 - x1);
double B = 1 - A;
return A * y1 + B * y2 + h2 / 6 * (A * (A * A - 1) * y1pp
+ B * (B * B - 1) * y2pp);
}
public double GetYp(double x)
{
int i = IndexOf(x);
double x1 = xi[i];
double x2 = xi[i + 1];
double y1 = yi[i];
double y2 = yi[i + 1];
double y1pp = ypp[i];
double y2pp = ypp[i + 1];
double h = x2 - x1;
double A = 1 - (x - x1) / (x2 - x1);
double B = 1 - A;
return (y2 - y1) / h + h / 6 * (y2pp * (3 * B * B - 1)
- y1pp * (3 * A * A - 1));
}
public double GetYpp(double x)
{
int i = IndexOf(x);
double x1 = xi[i];
double x2 = xi[i + 1];
double y1pp = ypp[i];
double y2pp = ypp[i + 1];
double h = x2 - x1;
double A = 1 - (x - x1) / (x2 - x1);
double B = 1 - A;
return A * y1pp + B * y2pp;
}
public double GetYppp(double x)
{
int i = IndexOf(x);
double x1 = xi[i];
double x2 = xi[i + 1];
double y1pp = ypp[i];
double y2pp = ypp[i + 1];
double h = x2 - x1;
return (y2pp - y1pp) / h;
}
public double Integrate(double from_x, double to_x)
{
if( to_x < from_x ) { return -Integrate(to_x, from_x); }
int i = IndexOf(from_x);
int j = IndexOf(to_x);
double x1 = xi[i];
double xn = xi[j];
double z = GetIntY(to_x) - GetIntY(from_x); // go to nearest nodes (k) (j)
for( int k = i + 1; k <= j; k++ )
{
z += iy[k]; // fill-in areas in-between
}
return z;
}
#endregion
#region Properties
public bool IsEmpty { get { return xi.Length == 0; } }
public double[] Xi { get { return xi; } set { xi = value; } }
public double[] Yi { get { return yi; } set { yi = value; } }
public double[] Yp { get { return yp; } set { yp = value; } }
public double[] Ypp { get { return ypp; } set { ypp = value; } }
public double[] Yppp { get { return yppp; } set { yppp = value; } }
public double[] IntY { get { return yp; } set { iy = value; } }
public int Count { get { return xi.Length; } }
public double X_min { get { return xi.Min(); } }
public double X_max { get { return xi.Max(); } }
public double Y_min { get { return yi.Min(); } }
public double Y_max { get { return yi.Max(); } }
#endregion
#region Helpers
static double[] Sequence(double x_min, double x_max, int double_of_points)
{
double[] res = new double[double_of_points];
for (int i = 0; i < double_of_points; i++)
{
res[i] = x_min + (double)i / (double)(double_of_points - 1) * (x_max - x_min);
}
return res;
}
#endregion
}
You can find an approximation of a line that intersects points in 3d and 2d space using a Hough Transformation algorithm. I am only familiar with it's uses in 2d however but it will still work for 3d spaces given that you know what kind of line you are looking for. There is a basic implementation description linked. You can Google for pre-mades and here is a link to a 2d C implementation CImg.
The algorithm process (roughly)... First you find equation of a line that you think will best approximate the shape of the line (in 2d parabolic, logarithmic, exponential, etc). You take that formula and solve for one of the parameters.
y = ax + b
becomes
b = y - ax
Next, for each point you are attempting to match, you plugin the points to the y and x values. With 3 points, you would have 3 separate functions of b with respect to a.
(2, 3) : b = 3 - 2a
(4, 1) : b = 1 - 4a
(10, -5): b = -5 - 10a
Next, the theory is that you find all possible lines which pass through each of the points, which is infinitely many for each individual point however when combined in an accumulator space only a few possible parameters best fit. In practice this is done by choosing a range space for the parameters (I chose -2 <= a <= 1, 1 <= b <= 6) and begin plugging in values for the variant parameter(s) and solving for the other. You tally up the number of intersections from each function in an accumulator. The points with the highest values give you your parameters.
Accumulator after processing b = 3 - 2a
a: -2 -1 0 1
b: 1
2
3 1
4
5 1
6
Accumulator after processing b = 1 - 4a
a: -2 -1 0 1
b: 1 1
2
3 1
4
4
5 2
6
Accumulator after processing b = -5 - 10a
a: -2 -1 0 1
b: 1 1
2
3 1
4
5 3
6
The parameter set with the highest accumulated value is (b a) = (5 -1) and the function best fit to the points given is y = 5 - x.
Best of luck.
My guess is that a serious application of this would use a http://en.wikipedia.org/wiki/Kalman_filter. By the way, that probably wouldn't guarantee that the reported points were intersected either, unless you fiddled with the parameters a bit. It would expect some degree of error in each data point given to it, so where it thinks the object is at time T would not necessarily be where it was at time T. Of course, you could set the error distribution to say that you were absolutely sure you knew where it was at time T.
Short of using a Kalman filter, I would try and turn it into an optimisation problem. Work at the 1s granularity and write down equations like
x_t' = x_t + (Vx_t + Vx_t')/2 + e,
Vx_t_reported = Vx_t + f,
Vx_t' = Vx_t + g
where e, f, and g represent the noise. Then create a penalty function such as e^2 + f^2 + g^2 +...
or some weighted version such as 1.5e^2 + 3f^2 + 2.6g^2 +... according to your idea of what the errors really are and how smooth you wnat the answer to be, and find the values that make the penalty function as small as possible - with least squares if the equations turn out nicely.