C# v1 and v2 does not exist

I do not know what is wrong with my code. The v1 and the 2 are defined. And I do not want to copy the code of double newStart and the for-loop behind the else if because than the code will become too long.

What is a better solution :slight_smile:

  List<double> rangeByDistanceAtMid(double start, double end, double distance){
    List<double> range = new List<double>();
    if(start == end){range.Add(start); return range;}
    else if(start < end){double v1 = start; double v2 = end;}
    else if(start > end){double v1 = end;double v2 = start;}
    double newStart = (((v2 - v1) % distance) / 2) + v1;
    for(double v = newStart; v < v2; v += distance){range.Add(v);}
    return range;}

Same code but then less compact :slight_smile:

  List<double> rangeByDistanceAtMid(double start, double end, double distance)
  {
    List<double> range = new List<double>();
    if(start == end)
    {
      range.Add(start); return range;
    }
    else if(start < end)
    {
      double v1 = start; double v2 = end;
    }
    else if(start > end)
    {
      double v1 = end;double v2 = start;
    }
    double newStart = (((v2 - v1) % distance) / 2) + v1;
    for(double v = newStart; v < v2; v += distance)
    {
      range.Add(v);
    }
    return range;
  }

The longer code is not “too long”. Instead the shorter code is unreadable.

// Rolf

1 Like

I think it is a good learning experience to look at code formatted by professional programmers. An example here:

(Click on the link “show original” and scroll down. That is professional code.

Again, code must be readable. If not, it’s worthless. Code needs to be maintained, debugged, and often readable by others (as to no provoke introducing even more bugs, aso).

Compacting code like the first snippet in the first post is exactly what you should not do.

// Rolf

1 Like
List<double> rangeByDistanceAtMid(double start, double end, double distance) {
	List<double> range = new List<double>();
	if(start == end) {
		range.Add(start); return range;
	}
	else if(start < end) {
		double v1 = start; double v2 = end;
	}
	else if(start > end) {
		double v1 = end;double v2 = start;
	}
	double newStart = (((v2 - v1) % distance) / 2) + v1;
	for(double v = newStart; v < v2; v += distance) {
		range.Add(v);
	}
	return range;
}
1 Like
double[] rangeByDistanceAtMid(double start, double end, double distance)
  {
    if (start == end)
      return new double[] { start };
    
    double v1 = Math.Min(start, end);
    double v2 = Math.Max(start, end);
    double vm = 0.5 * ((v2 - v1) % distance) + v1;

    List<double> range = new List<double>();
    for(double v = vm; v < v2; v += distance)
      range.Add(v);
    
    return range.ToArray();
  }

My reformatting. I would never write a for loop based floating point equalities, but that would require a redesign.

1 Like

#cliffhanger

You know of something better? So, not a ‘for loop based floating point equalities,’ but? :thinking:

sorry I am not a c# guru but what is that
double newStart = (((v2 - v1) % distance) / 2) + v1; for ???

the mid value is = (v1+v2) *0.5;

1 Like

And sometimes the longer code is faster / more efficient than the shortcuts (think linq)

1 Like

I want a centric-orientated range, to illustrate:

Example A; -4 to 4; distance by 1.5; -1.5, 0, 1.5
Example B; -7 to 7; distance by 1.5; -6, -4.5, -3, -1.5, 0, 1.5, 3, 4.5, 6

I called it rangeByDistanceAtMid but I do not know if that is the best naming. For that, I need to change something in the formula.

I now type it like Joseph and David and took Rolf’s example.

Here is the new version, ‘how to redesign it’ where you put the cliffhanger at?
(I do not know yet where to exactly ‘public or private yet’ public or private or something else as Rolf’s example, but this is what I have).

  List<double> rangeByDistanceAtMid(double start, double end, double distance){
    List<double> range = new List<double>();
    if (start == end){
      range.Add(start); return range;
    }
    double v1 = Math.Min(start, end);
    double v2 = Math.Max(start, end);
    //double vm = (((v2 - v1) % distance) / 2) + v1;
    double vm = ((((v2 - v1) / 2) % distance) + v1);
    for(double v = vm; v < v2; v += distance)
      range.Add(v);
    return range;
  }

question5.gh (7.9 KB)

"
List rangeByDistanceAtMid(double start, double end, double distance){
{
List range = new List();

    double _midP =(start+end)*0.5;
    double _start = Math.Min(start,end); 
    double _end = Math.Max(start,end); 


    double stV = _midP;
    do
    {
        range.Add(stV);
        stV+=distance;
    }while( stV< _end  );  
        
     return range;

}
"

my version

1 Like

The problem with floating point numbers is that you can never use equality on two numbers which are the result of some computation. Because the least significant digits of a floating point number are untrustworthy once you’ve performed an addition, subtraction, multiplication or division.

Oftentimes it will work as you expect, and then sometimes, under some very special condition it rounds the other way and boom, your sequence now contains fewer or more numbers than you wanted. Developing algorithms which correctly deal with floating point numbers is difficult. Oftentimes impossible. Best you can do is kinda-sorta-correct, and even that can be hard.

middle sequence.gh (10.9 KB)

I’ve added many comments in the file to explain some of the choices I’ve made, but I’ve removed them here to shrink the wall-o-code.

double[] CentredSequence(double start, double end, double stepsize)
{
  double min = Math.Min(start, end);
  double max = Math.Max(start, end);
  stepsize = Math.Abs(stepsize);
  if (stepsize == 0.0)
    throw new Exception("Stepsize may not be zero.");

  double mid = 0.5 * min + 0.5 * max;

  if (max - min < stepsize)
    return new double[] { mid };

  const double tolerance = 1e-8;
  int halfcount = (int) ((mid - min) / stepsize + tolerance);
  int count = 2 * halfcount + 1;

  double offset = (mid - min) - halfcount * stepsize;
  double[] sequence = new double[count];
  for (int i = 0; i < sequence.Length; i++)
    sequence[i] = min + i * stepsize + offset;

  return sequence;
}
1 Like

As a side note, the increment instruction v += distance in this loop:

for(double v = vm; v < v2; v += distance)

is particularly bad. Every floating point error you encounter during the running of this loop will become part of the sequence; they are cumulative. Okay, some of them will cancel out against others, but you definitely want to avoid that if at all possible.

Even worse, it may cause the loop to never terminate at all. Every floating point number has 15 to 16 decimal places, regardless of its magnitude. (But let’s say it’s only 4 to make this explanation somewhat easier.)

So if you compute \frac{1.0}{3.0} you get the result 0.3333, with all remaining digits implied to be zero. But calculate \frac{1000000.0}{3.0}, and your result will be 333300.0. You’re not allowed to store more than four digits in your number, so the least significant ones are dropped from the calculation.

Now what happens if you compute \frac{1000000.0}{3.0} + \frac{1.0}{3.0}? That’s right, the addition just disappears. In floating point maths, a+b=a whenever the magnitude of b is less than the least significant digit of a. So that original loop could end up in a state where v += distance always just yields v over and over again, and therefore v will never become larger than v2.

4 Likes

Thank you for your very clear explanation, I now continue reading it :grin:

I am now reading David’s answer. Besides that, I am still learning and try to teach myself all solutions in order to get experience and becoming better in problem solving, a small question, based on your code, line 67 :thinking: what am I doing wrong?

question5a.gh (10.1 KB)

I think that

new List();

should be

new List<double>();

The message complains about the missing type, that is ‘double’

1 Like

code past , has removed all the “<” double “>” text , seems editor understood it was bad html code

1 Like

I would add at the begin as a side check :

double eps = 1.0e-10;
distance = Math.Abs( distance );
if( distance < eps ) return range;

1 Like

I read it, I studied it (bestuderen) and I learned from it, thank you David :smile: