Matematika - angka pemetaan

Jawaban:

211

Jika bilangan X Anda berada di antara A dan B, dan Anda ingin Y berada di antara C dan D, Anda dapat menerapkan transformasi linier berikut:

Y = (X-A)/(B-A) * (D-C) + C

Itu akan memberi Anda apa yang Anda inginkan, meskipun pertanyaan Anda agak ambigu, karena Anda juga bisa memetakan interval ke arah sebaliknya. Hati-hati terhadap pembagian dengan nol dan Anda akan baik-baik saja.

PeterAllenWebb
sumber
16
Untuk kejelasan, saya suka new_value = (old_value - old_bottom) / (old_top - old_bottom) * (new_top - new_bottom) + new_bottom;
ftrotter
1
Apakah ada penurunan persamaan ini di suatu tempat?
shaveenk
@shaveenk itu harus berupa persamaan garis, dengan Y=f(X)=m*X+b, di mana m dan b telah ditentukan secara bersamaan dari dua persamaan kendala berikut yang dihasilkan dari penggantian nilai X dan Y pada titik akhir yang diperlukan: C=m*A+bdanD=m*B+b
Chris Chiasson
Saya juga akhirnya perlu menggunakan X=A+(A-B)*tuntuk membuktikan kesetaraan antara pendekatan ini dan Peter. t pada dasarnya adalah nondimensionalization dari X. ( t=(X-A)/(A-B))
Chris Chiasson
Untuk membalikkan arah, rumusnya adalah ((XA) / (AB) * (CD)) * -1 + D
Corey Levinson
21

Bagilah untuk mendapatkan rasio antara ukuran kedua rentang, lalu kurangi nilai awal rentang awal Anda, kalikan dengan rasio dan tambahkan nilai awal rentang kedua Anda. Dengan kata lain,

R = (20 - 10) / (6 - 2)
y = (x - 2) * R + 10

Ini menyebarkan angka secara merata dari kisaran pertama di kisaran kedua.

Konrad Rudolph
sumber
Ini tidak berhasil. Jangkauan saya adalah 1000000000 hingga 9999999999 dan angkanya bisa dari 1 hingga 999999999.
Dejell
@Odelya Tentu saja berhasil. Ini adalah transformasi matematis yang cukup sederhana. Anda hanya perlu menggunakan jenis angka yang cukup besar (bignum atau sejenisnya). Angka Anda terlalu besar untuk bilangan bulat 32 bit - tetapi bilangan bulat 64 bit misalnya akan berfungsi.
Konrad Rudolph
Mereka adalah tipe ganda. ganda R = (20 - 10) / (6 - 2); ganda y = (X - 2) * R + 10;
Dejell
@Odelya Masalahnya sama. Anda harus membaca tentang presisi floating-point. Faktanya, ini adalah bacaan wajib: Yang Harus Diketahui Setiap Ilmuwan Komputer Tentang Aritmatika Titik-Apung - jika Anda membutuhkan tipe titik-mengambang dengan bilangan yang begitu besar, Anda mungkin harus menggunakan tipe bilangan presisi-arbitrer .
Konrad Rudolph
Dapatkah Anda merekomendasikan tipe java yang bisa saya lakukan?
Dejell
7

Akan menyenangkan memiliki fungsi ini di java.lang.Mathkelas, karena ini adalah fungsi yang sangat dibutuhkan dan tersedia dalam bahasa lain. Berikut ini implementasi sederhana:

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;
}

Saya meletakkan kode ini di sini sebagai referensi untuk diri saya di masa depan dan mungkin itu akan membantu seseorang.

Sourabh Bhat
sumber
4

Selain itu, ini adalah masalah yang sama dengan klasik mengubah celcius ke farenheit di mana Anda ingin memetakan rentang angka yang menyamakan 0 - 100 (C) menjadi 32 - 212 (F).

Metro
sumber
Bagaimana ini jawabannya?
shinzou
Ini adalah contoh penerapan pertanyaan. Banyak yang memiliki masalah sederhana ini di kelas pengantar CS dan tidak menganggap bahwa solusinya dapat digeneralisasikan ke masalah lain. Saya mencoba menambahkan konteks ke pertanyaan asli. Pertanyaan asli sudah dijawab dengan memadai.
Metro
1

Setiap interval satuan pada kisaran pertama membutuhkan (dc) / (ba) "spasi" pada kisaran kedua.

Semu:

var interval = (d-c)/(b-a)
for n = 0 to (b - a)
    print c + n*interval

Bagaimana Anda menangani pembulatan itu terserah Anda.

Chris Cudmore
sumber
1
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);

Tentu saja dengan memeriksa bagi dengan nol.

PhiLho
sumber
1

jika rentang Anda dari [a hingga b] dan Anda ingin memetakannya di [c ke d] di mana x adalah nilai yang ingin Anda petakan, gunakan rumus ini (pemetaan linier)

double R = (d-c)/(b-a)
double y = c+(x*R)+R
return(y)
Mohamed Ashraf
sumber
1

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)
Amerrnath
sumber
0

Selain jawaban @PeterAllenWebb, jika Anda ingin membalikkan kembali hasilnya, gunakan yang berikut:

reverseX = (B-A)*(Y-C)/(D-C) + A
Dejell
sumber