exponetial speed

Hi,
I am working on a project where I need to get numbers from 0^6 to 700^6.
the problem there is that 700^6 is 117.649.000.000.000.000, with is a big number. To make it smaler I devided it by 30.000.000 so that it fits into the unsigned long (it is now 3.921.633.333).
Now the problem:
As soon it goes higher than 40^6 it doesn’t work anymore. I guess it gets too big but I thought I would fix this by deviding it by 30.000.000. I was wrong…

Is there someone who can help me?

#include <math.h>

void setup()
{
Serial.begin(9600);

}
void loop()
{
  EaseInOut(40,6);  //as soon I change it into something hogher than 40 it doesn't work anymore....
}

void EaseInOut(double x, float e)
{

x = pow (x,e) / 3000000;   //I tried it with x*x*x*x*x*x but that didn't make a change either.

Serial.println (x);
}

What are you actually doing? Maybe we can find a better way if you provide more details.

Udo

to explain it simple: I want to make a servoarm with sweeps back an forth. The force that is been applied when the arm changes directions is much greater than when is moves just inso one direction. To reduce this force I want to make getting exponetially faster untill it reaches the middle and than exponantially decrease it. I would love to show you the curve but i have no clue how to insert a file...

I wanted to do 0^6 - 700^6 and than 700^6 - 0^6 (in a loop) and map into the right numbers for Servo.writeMicroseconds()

hope someone undestands it :)

700^6 should fit easily into a float…
http://arduino.cc/en/Reference/Float

u divide by 3000000, which is just 3e6, but not 3e7… one “0” is missing…

-arne

can u show us the output of this:

{
for (int i=0; i<=100; i+=10)
Serial.println(pow(i,6));
}

?

-arne

right at the point where it gets bigger than 4.294.967.295 (unsigned float)

It does that:

999999.68
63999980.00
728999872.00
4095998720.00
0.00
0.00
0.00
0.00
0.00
0.00
0.00
999999.68
63999980.00
728999872.00
4095998720.00
0.00
0.00
0.00
0.00
0.00
0.00
0.00
999999.68
63999980.00
728999872.00
4095998720.00
0.00
0.00
0.00
0.00
0.00
0.00
0.00
...
...

very interesting...

there might be a bug in the pow() implementation...

i will chk that... :-) wag tail

-arne

thank you :)

but there is the same problem when I do x*x*x*x*x*x shouldn't that work than?

yeah - u r right…pow() is good most likely…

it is a bug in Serial.print(float)

void setup() {
  Serial.begin(115200);
}

void myprintln(float f) {
  for (float m=1e30; m>0; m/=10) {
    const int d = f/m;
    f -= d*m;
    Serial.print(d);
  }
  Serial.println("");
}

void loop() {
  Serial.println("start:");
  for (int i=0; i<=100; i+=10)
    Serial.println(pow(i,6));
  myprintln(50e0*50e0*50e0*50e0*50e0*50e0);
}

-arne

What do I need to do with this? sadly I am not experienced enouth to fix it or see it :-[

Florian

do u need to print big float numbers?

if yes: use my function "myprintln"... i reported the bug here: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1273401607/0#0

-arne

hey I inserted your myprintln ant it printed that:

start:
0.00
999999.68
63999980.00
728999872.00
4095998720.00
0.00
0.00
0.00
0.00
0.00
0.00
0000000000000000000015624998267107866261084032093248583067778721939186200040
start:
0.00
999999.68
63999980.00
728999872.00
4095998720.00
0.00
0.00
0.00
0.00
0.00
0.00
0000000000000000000015624998267107866261084032093248583067778721939186200040

I don't need big float numbers I would map them into a 544 to 2400 range, but before that I need the numbers for calculating the increase and decrease.

the floating point arithmetrics r ok...

just the print out is currently bad... do u really need to print them? u could compute everything on the arduino, couldnt u?

-arne

I could do it without printing it, but it is easier to see if everything works.

then u should use this

void printFloat(double number, uint8_t digits)
{
  // Handle negative numbers
  if (number < 0) {
     Serial.print('-');
     number = -number;
  }
  // determine exponent
  const int8_t e = log(number) / log(10) - 8;
  number *= pow(10,-e);
  Serial.print((uint32_t)number);
  Serial.print('e');
  Serial.print(e);
}

until the bug is fixed…

-arne

I changed the print.cpp

with your code but it still didn’t work :frowning:

/*
 Print.cpp - Base class that provides print() and println()
 Copyright (c) 2008 David A. Mellis.  All right reserved.
 
 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.
 
 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 Modified 23 November 2006 by David A. Mellis
 */

#include <stdio.h>
#include <string.h>
#include <math.h>
#include "wiring.h"

#include "Print.h"

// Public Methods //////////////////////////////////////////////////////////////

/* default implementation: may be overridden */
void Print::write(const char *str)
{
  while (*str)
    write(*str++);
}

/* default implementation: may be overridden */
void Print::write(const uint8_t *buffer, size_t size)
{
  while (size--)
    write(*buffer++);
}

void Print::print(const char str[])
{
  write(str);
}

void Print::print(char c, int base)
{
  print((long) c, base);
}

void Print::print(unsigned char b, int base)
{
  print((unsigned long) b, base);
}

void Print::print(int n, int base)
{
  print((long) n, base);
}

void Print::print(unsigned int n, int base)
{
  print((unsigned long) n, base);
}

void Print::print(long n, int base)
{
  if (base == 0) {
    write(n);
  } else if (base == 10) {
    if (n < 0) {
      print('-');
      n = -n;
    }
    printNumber(n, 10);
  } else {
    printNumber(n, base);
  }
}

void Print::print(unsigned long n, int base)
{
  if (base == 0) write(n);
  else printNumber(n, base);
}

void Print::print(double n, int digits)
{
  printFloat(n, digits);
}

void Print::println(void)
{
  print('\r');
  print('\n');  
}

void Print::println(const char c[])
{
  print(c);
  println();
}

void Print::println(char c, int base)
{
  print(c, base);
  println();
}

void Print::println(unsigned char b, int base)
{
  print(b, base);
  println();
}

void Print::println(int n, int base)
{
  print(n, base);
  println();
}

void Print::println(unsigned int n, int base)
{
  print(n, base);
  println();
}

void Print::println(long n, int base)
{
  print(n, base);
  println();
}

void Print::println(unsigned long n, int base)
{
  print(n, base);
  println();
}

void Print::println(double n, int digits)
{
  print(n, digits);
  println();
}

// Private Methods /////////////////////////////////////////////////////////////

void Print::printNumber(unsigned long n, uint8_t base)
{
  unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars. 
  unsigned long i = 0;

  if (n == 0) {
    print('0');
    return;
  } 

  while (n > 0) {
    buf[i++] = n % base;
    n /= base;
  }

  for (; i > 0; i--)
    print((char) (buf[i - 1] < 10 ?
      '0' + buf[i - 1] :
      'A' + buf[i - 1] - 10));
}

void Print::printFloat(double number, uint8_t digits)
{
  if (number == 0) {
    print("0e0");
    return;
  }
  // Handle negative numbers
  if (number < 0) {
     print('-');
     number = -number;
  }
  // determine exponent
  const int8_t e = log(number) / log(10) - 8;
  number *= pow(10,-e);
  print((uint32_t)number);
  print('e');
  print(e);
}

hm sorry - i missed the 2nd page of this thread...

in what way does it fail?

-arne

I want to make a servoarm with sweeps back an forth. The force that is been applied when the arm changes directions is much greater than when is moves just inso one direction. To reduce this force I want to make getting exponetially faster untill it reaches the middle and than exponantially decrease it.

While it is interesting that a bug was discovered, something tells me that you wanting to use such HUGE numbers (seriously, these are very huge numbers) means that you may be overthinking the solution you are trying to implement.

Its kinda like car racing; sure, you can make a car go faster by putting a bigger engine in it - but you can also do it by reducing weight and drag…

[edit]BTW - you may want to look into a PID controller for your servo…it may help in such an application.[/edit]

Yeah, that was my thought as well. With servos, on an arduino...

1) the servo electronics are going to do some of this for you. In fact, if you guess wrong and make your interval too small, the servo may move faster than your interval, causing it to stop and making the problem worse instead of better. 2) What you really want (IMO) is to move the servo over fixed intervals with variable timing, rather than variable intervals with fixed timing. 3) The range of servo endpoints is rather small compare to the graphics environment of the original examples ("easing"), so it probably makes sense to divide a movement into a fixed number of intervals, at which point all of your polynomial pieces of functions become constants:

moveservo(startpoint, endpoint, whichstep)
{  // move from start to endpoint using 14 steps, with the distance moved in each
   // step determined by how close you are to the endpoints.
   // 14 is chosen so that the main part of the move will be 8ths of the interval, for easy math

   distancefromend = min(whichstep, 14-whichstep);
   switch (disancefromend) {
    case 0: stepsize = 1; break;
    case 1: stepsize = 2; break;
    case 2: stepsize = 4; break;
    default: stepsize = ((endpoint-startpoint)-14)/8; break;
}

Let's see 0 to 100 would give me

Step:     1  2  3  4   5    6   7   8   9  10  11 12 13 14
Stepsize: 1, 2, 4, 10, 10, 10, 10, 10, 10, 10, 10, 4, 2, 1
Distance:   1  3  7  17  27  37  47  57  67  77  87 91 93 94

That's not perfect; you'd have to do something to solve the roundoff error problem, and it'll fail dramatically for movements less than 14. But the idea i easily modified, easily analyzed, and doesn't require complex math.

Looks interresting. but a little ruff, there needs to be a smooter way, but that can be fixed ^^