Adc Conversion quantization - java

double vDeltaRef, vPlusRef = 10, vMinusRef = 0, q, n, nExp = 3;
vDeltaRef = vPlusRef - vMinusRef;
n = Math.pow(2, nExp);
q = vDeltaRef / n;
System.out.println(q);
the result from the formula is 1.25v
this value:
How can I translate the obtained result

Since you know vPlusRef, vMinusRef and nExp, you can always calculate q (which is 1.25 in this case).
Then, to convert from digital to analog simply multiply the digital value with q. For example the 3-bit value 011, which is 3 in decimal, will be converted to 3.75 which is the lower bound of the required range 3.75 to 5.00.
Finally, to convert from analog to digital do:
int digitalValue = (int) Math.floor(analogValue / q);
For example an analog value of 8.19 would return 6, which is the 3-bit value 110.

Related

Generate random float, both bounds inclusive

I need to generate random real numbers in the range [-0.5, 0.5], both bounds inclusive.
I found various ways to generate similar ranges, like
-0.5 + Math.random()
But the upper bound is always exclusive, I need it inclusive as well. 0.5 must be inside the range.
One way to achieve this would be to create random int from -500 to 500 and then divide it by 1000.
int max = 500;
int min = -500;
int randomInt = rand.nextInt((max - min) + 1) + min;
float randomNum = randomInt / 1000.00f;
System.out.println(randomNum);
You can change the precision by adding and removing zeros from the integer boundaries and the divisor. (eG: create integers from -5 to +5 and divide by 10 for less precision)
A disadvantage of that solution is that it does not use the maximum precision provided by float/double data types.
I haven't seen any answer that uses bit-fiddling inside the IEEE-754 Double representation, so here's one.
Based on the observation that a rollover to a next binary exponent is the same as adding 1 to the binary representation (actually this is by design):
Double.longBitsToDouble(0x3ff0000000000000L) // 1.0
Double.longBitsToDouble(0x3ffFFFFFFFFFFFFFL) // 1.9999999999999998
Double.longBitsToDouble(0x4000000000000000L) // 2.0
I came up with this:
long l = ThreadLocalRandom.current().nextLong(0x0010000000000001L);
double r = Double.longBitsToDouble(l + 0x3ff0000000000000L) - 1.5;
This technique works only with ranges that span a binary number (1, 2, 4, 8, 0.5, 0.25, etc) but for those ranges this approach is possibly the most efficient and accurate. This example is tuned for a span of 1. For ranges that do not span a binary range, you can still use this technique to get a different span. Apply the technique to get a number in the range [0, 1] and scale the result to the desired span. This has negligible accuracy loss, and the resulting accuracy is actually identical to that of Random.nextDouble(double, double).
For other spans, execute this code to find the offset:
double span = 0.125;
if (!(span > 0.0) || (Double.doubleToLongBits(span) & 0x000FFFFFFFFFFFFFL) != 0)
throw new IllegalArgumentException("'span' is not a binary number: " + span);
if (span * 2 >= Double.MAX_VALUE)
throw new IllegalArgumentException("'span' is too large: " + span);
System.out.println("Offset: 0x" + Long.toHexString(Double.doubleToLongBits(span)));
When you plug this offset into the second line of the actual code, you get a value in the range [span, 2*span]. Subtract the span to get a value starting at 0.
You can adjust the upper bound by the minimal value (epsilon) larger than the maxium value you expect. To find the epsilon, start with any positive value and make it as small as it can get:
double min = -0.5;
double max = 0.5;
double epsilon = 1;
while (max + epsilon / 2 > max) {
epsilon /= 2;
}
Random random = ThreadLocalRandom.current();
DoubleStream randomDoubles = random.doubles(min, max + epsilon);
Edit: alternative suggested by #DodgyCodeException (results in same epsilon as above):
double min = -0.5;
double max = 0.5;
double maxPlusEpsilon = Double.longBitsToDouble(Double.doubleToLongBits(max) + 1L)
Random random = ThreadLocalRandom.current();
DoubleStream randomDoubles = random.doubles(min, maxPlusEpsilon);
Given HOW GOD SPIDERS answer, here is a ready to use function :
public static double randomFloat(double minInclusive, double maxInclusive, double precision) {
int max = (int)(maxInclusive/precision);
int min = (int)(minInclusive/precision);
Random rand = new Random();
int randomInt = rand.nextInt((max - min) + 1) + min;
double randomNum = randomInt * precision;
return randomNum;
}
then
System.out.print(randomFloat(-0.5, 0.5, 0.01));
#OH GOD SPIDERS' answer gave me an idea to develop it into an answer that gives greater precision. nextLong() gives a value between MIN_VALUE and MAX_VALUE with more than adequate precision when cast to double.
double randomNum = (rand.nextLong() / 2.0) / Long.MAX_VALUE;
Proof that bounds are inclusive:
assert (Long.MIN_VALUE/2.0)/Long.MAX_VALUE == -0.5;
assert (Long.MAX_VALUE/2.0)/Long.MAX_VALUE == 0.5;
Random.nextDouble gives a value in the range of [0, 1]. So to map that to a range of [-0.5, 0.5] you just need to subtract by 0.5.
You can use this code to get the desired output
double value = r.nextDouble() - 0.5;

java StdDraw formula for ratio [duplicate]

How do I map numbers, linearly, between a and b to go between c and d.
That is, I want numbers between 2 and 6 to map to numbers between 10 and 20... but I need the generalized case.
My brain is fried.
If your number X falls between A and B, and you would like Y to fall between C and D, you can apply the following linear transform:
Y = (X-A)/(B-A) * (D-C) + C
That should give you what you want, although your question is a little ambiguous, since you could also map the interval in the reverse direction. Just watch out for division by zero and you should be OK.
Divide to get the ratio between the sizes of the two ranges, then subtract the starting value of your inital range, multiply by the ratio and add the starting value of your second range. In other words,
R = (20 - 10) / (6 - 2)
y = (x - 2) * R + 10
This evenly spreads the numbers from the first range in the second range.
It would be nice to have this functionality in the java.lang.Math class, as this is such a widely required function and is available in other languages.
Here is a simple implementation:
final static double EPSILON = 1e-12;
public static double map(double valueCoord1,
double startCoord1, double endCoord1,
double startCoord2, double endCoord2) {
if (Math.abs(endCoord1 - startCoord1) < EPSILON) {
throw new ArithmeticException("/ 0");
}
double offset = startCoord2;
double ratio = (endCoord2 - startCoord2) / (endCoord1 - startCoord1);
return ratio * (valueCoord1 - startCoord1) + offset;
}
I am putting this code here as a reference for future myself and may be it will help someone.
As an aside, this is the same problem as the classic convert celcius to farenheit where you want to map a number range that equates 0 - 100 (C) to 32 - 212 (F).
https://rosettacode.org/wiki/Map_range
[a1, a2] => [b1, b2]
if s in range of [a1, a2]
then t which will be in range of [b1, b2]
t= b1 + ((s- a1) * (b2-b1))/ (a2-a1)
In addition to #PeterAllenWebb answer, if you would like to reverse back the result use the following:
reverseX = (B-A)*(Y-C)/(D-C) + A
Each unit interval on the first range takes up (d-c)/(b-a) "space" on the second range.
Pseudo:
var interval = (d-c)/(b-a)
for n = 0 to (b - a)
print c + n*interval
How you handle the rounding is up to you.
if your range from [a to b] and you want to map it in [c to d] where x is the value you want to map
use this formula (linear mapping)
double R = (d-c)/(b-a)
double y = c+(x*R)+R
return(y)
Where X is the number to map from A-B to C-D, and Y is the result:
Take the linear interpolation formula, lerp(a,b,m)=a+(m*(b-a)), and put C and D in place of a and b to get Y=C+(m*(D-C)). Then, in place of m, put (X-A)/(B-A) to get Y=C+(((X-A)/(B-A))*(D-C)). This is an okay map function, but it can be simplified. Take the (D-C) piece, and put it inside the dividend to get Y=C+(((X-A)*(D-C))/(B-A)). This gives us another piece we can simplify, (X-A)*(D-C), which equates to (X*D)-(X*C)-(A*D)+(A*C). Pop that in, and you get Y=C+(((X*D)-(X*C)-(A*D)+(A*C))/(B-A)). The next thing you need to do is add in the +C bit. To do that, you multiply C by (B-A) to get ((B*C)-(A*C)), and move it into the dividend to get Y=(((X*D)-(X*C)-(A*D)+(A*C)+(B*C)-(A*C))/(B-A)). This is redundant, containing both a +(A*C) and a -(A*C), which cancel each other out. Remove them, and you get a final result of: Y=((X*D)-(X*C)-(A*D)+(B*C))/(B-A)
TL;DR: The standard map function, Y=C+(((X-A)/(B-A))*(D-C)), can be simplified down to Y=((X*D)-(X*C)-(A*D)+(B*C))/(B-A)
int srcMin = 2, srcMax = 6;
int tgtMin = 10, tgtMax = 20;
int nb = srcMax - srcMin;
int range = tgtMax - tgtMin;
float rate = (float) range / (float) nb;
println(srcMin + " > " + tgtMin);
float stepF = tgtMin;
for (int i = 1; i < nb; i++)
{
stepF += rate;
println((srcMin + i) + " > " + (int) (stepF + 0.5) + " (" + stepF + ")");
}
println(srcMax + " > " + tgtMax);
With checks on divide by zero, of course.

Java BigInteger(byte[] val)

I am trying to understand how does the java.math.BigInteger.BigInteger(byte[] val) constructor work.
For example when I create a BigInteger instance from the byte array [1, 0], the corresponding string it creates is 256. Surely, the binary string 10 corresponds to value 2 in base 10. How does it convert it from 10 to 256? What am I missing?
Each byte in the array represents 8 bits, so [1, 0] is equivalent to 1 * 2^(8 * 1) + 0 * 2^(8 * 0), or, in binary: 00000001 00000000.
Beware that the BigInteger (byte[]) constructor also uses two's complement, so it's not just a matter of adding the unsigned numbers: the most significant bit will affect the sign.
It's effectively working in base-256, not base-2. So each position in the input array is worth 256 times more than the next position.
Pseudo-code:
x = 0;
for (i = 0; i < val.length - 1; i++) {
x = (x*256) + val[i];
}

How to use the equivalent of indexof() with biginteger in VB.Net?

I am trying to sum up the digits in a very large number. I have gotten the length of the number with
l = answer.bitLength() but I can't figure out how to increament through each digit using a For loop. Any ideas?
I'm using the java.math.biginteger.
Visual Studio 2005 Version 2.0
I should also add that I can't seem to use <> or any of the simple math options with the biginteger I'm using. If anyone could tell me how to use a different biginteger I would be more than willing to swap.
Dim answer As java.math.BigInteger
Dim sum As Integer = 0
Dim x As Integer
Dim i As Integer
'Sets value of answer equal to 1
answer = java.math.BigInteger.valueOf(1)
'gets 100!
For i = 1 To 100
answer = answer.multiply(java.math.BigInteger.valueOf(i))
Next
'gets length of answer
Dim l As Integer
l = answer.bitLength()
'Sums up digits in 100!
For x = 0 To l - 1
'Need to pull each character here to add them all up
Next
Final Solution for summing up the digits. Thanks to wageoghe.
Dim r As Integer
Dim s As Integer
s = 0
While (answer.compareTo(java.math.BigInteger.valueOf(0)) > 0)
r = answer.mod(java.math.BigInteger.valueOf(10)).ToString()
s = s + r
answer = answer.divide(java.math.BigInteger.valueOf(10))
End While
Something like this should work:
Dim bi As New System.Numerics.BigInteger(12345)
Dim c As Char
Dim s As Long
s = 0
For Each c In bi.ToString()
s = s + Integer.Parse(c.ToString())
Next
Or this more conventional way using Mod and / (integer division)
Dim bi As New System.Numerics.BigInteger(12345)
Dim s As Long
Dim r As Integer
s = 0
While bi <> 0
r = bi Mod 10
s = s + r
bi = bi / 10
End While
If you think of the number as a list of binary characters, then you could get the least significant hex digit by ANDing the number with 0xF. If you then shifted the number right by 4 bits (>> 4), then you could get the next hex digit.
After you get all of the hex digits, you could sum them up and then convert them to decimal.
Another approach, is to do the following (this assumes that answer is positive):
int sum = 0;
while(answer > 0){
sum += answer % 10;
answer /= 10;
}

Why is this true?

This is IEEE 754 standard question. I don't completely understand the mechanics behind it.
public class Gray {
public static void main(String[] args){
System.out.println( (float) (2000000000) == (float) (2000000000 + 50));
}
}
Because a float can only hold about 7 to 8 significant digits. That is, it doesn't have enough bits to represent the number 2000000050 exactly, so it gets rounded to 2000000000.
Specifically speaking, a float consists of three parts:
the sign bit (1 bit)
the exponent (8 bits)
the significand (24 bits, but only 23 bits are stored since the MSB of the significand is always 1)
You can think of floating point as the computer's way doing scientific notation, but in binary.
The precision is equal to log(2 ^ number of significand bits). That means a float can hold log(2 ^ 24) = 7.225 significant digits.
The number 2,000,000,050 has 9 significant digits. The calculation above tells us that a 24-bit significand can't hold that many significant digits. The reason why 2,000,000,000 works because there's only 1 significant digit, so it fits in the significand.
To solve the problem, you would use a double since it has a 52-bit significand, which is more than enough to represent every possible 32-bit number.
Plainly said - 50 is a rounding error when a float has a value of two-billion.
You might find this trick to find the next representable value interesting.
float f = 2000000000;
int binaryValue = Float.floatToRawIntBits(f);
int nextBinaryValue = binaryValue+1;
float nextFloat = Float.intBitsToFloat(nextBinaryValue);
System.out.printf("The next float value after %.0f is %.0f%n", f, nextFloat);
double d = 2000000000;
long binaryValue2 = Double.doubleToRawLongBits(d);
long nextBinaryValue2 = binaryValue2+1;
double nextDouble = Double.longBitsToDouble(nextBinaryValue2);
System.out.printf("The next double value after %.7f is %.7f%n", d, nextDouble);
prints
The next float value after 2000000000 is 2000000128
The next double value after 2000000000.0000000 is 2000000000.0000002
It might help you understand the situation if you consider a program (C++) as below. It displays the groups of successive integers that get rounded to the same float value:
#include <iostream>
#include <iomanip>
int main()
{
float prev = 0;
int count = 0;
double from;
for (double to = 2000000000 - 150; count < 10; to += 1.0)
{
float now = to;
if (now != prev)
{
if (count)
std::cout << std::setprecision(20) << from << ".." << to - 1 << " ==> " << prev << '\n';
prev = now;
from = to;
++count;
}
}
}
Output:
1999999850..1999999935 ==> 1999999872
1999999936..2000000064 ==> 2000000000
2000000065..2000000191 ==> 2000000128
2000000192..2000000320 ==> 2000000256
2000000321..2000000447 ==> 2000000384
2000000448..2000000576 ==> 2000000512
2000000577..2000000703 ==> 2000000640
2000000704..2000000832 ==> 2000000768
2000000833..2000000959 ==> 2000000896
This indicates that floating point is only precise enough to represent all integers from 1999999850 to 1999999935, wrongly recording their value as 1999999872. So on for other values. This is the tangible consequence of the limited storage space mentioned above.

Categories

Resources