2016-04-13 38 views
0

departure = [x,y] ve destination = [x,y] verilen iki nokta arasındaki mesafeyi buluyorum. X veya y ile, her zaman bir kayan nokta ve diğeri int, bu yüzden her zaman bir satırda. Hedef noktaya ulaşmak için kılavuz çizgileri üzerinde kalmanız gerekir ve hiçbir ek artış yoktur. Ben burada inters ve floats karışımı ile ilgilenen bir ızgara üzerinde mesafe bulma konusunda herhangi bir mesaj görmedim. Izgarada 2 nokta arasındaki mesafeyi bulun

Bu

benim kodudur:

def perfectCity(departure, destination): 
    return abs(destination[0]-departure[0]) + abs(destination[1]-departure[1]) 

bir örnek departure = [0.4, 1] ve destination = [0.9, 3] olacağını, bu 2.7 eşit olmalıdır, ama ben 2.5

Örneğin, [1, 3][0.9, 3] ila [1, 1] için [0.4, 1] gitmek olsun Toplam 2.7 fark için. Manhattan mesafesini hesaplamak gibidir, ancak kafes noktalarından başlamak ve bitirmek yerine, bir bloğun yarısına kadar başlayıp/veya sona erdirebilirsiniz.

+0

hemen hemen her zaman yuvarlama hatası biraz var yüzer. Baz 10'daki sonlu ondalık açılımlar her zaman temel 2 –

+2

'daki sonlu ondalık açılımlar değildir. [Kayan nokta matematik bozuk mu?] (Http://stackoverflow.com/questions/588004/is-floating-point-math-broken) olası kopyası –

+0

Onun bir kopya olduğunu düşünmüyorum, çünkü onun bir açık nokta hatası, diğer iş parçacığı kendi açık bilmeniz gerekir. – JonnyDoeInWisco

cevap

2

, bu gibi görünüyor Naif Manhattan mesafesi, yolunuz "C" şeklini aldığında (örnekte verildiği gibi) hariç çalışacaktır. Bu, iki şamandıra noktanızın hem x koordinatları hem de y koordinatları ve aynı tamsayı parçasına sahip olması durumunda gerçekleşecektir. Her Evden

def minimum_distance(p1, p2): 

    i1, i2 = int(p1[0]), int(p2[0]) 

    # if both x-coordinates are floats and they have the same integer part 
    if i1 != p1[0] and i2 != p2[0] and i1 == i2: 

     # find the decimal parts 
     d1, d2 = p1[0] - i1, p2[0] - i2 

     # find the smaller "C" 
     x = min(d1 + d2, (1-d1) + (1-d2)) 

     # add the y distance to the "C" distance 
     return abs(p1[1] - p2[1]) + x 

    # repeat with the "y-coordinates are floats" case 
    i1, i2 = int(p1[1]), int(p2[1]) 
    if i1 != p1[1] and i2 != p2[1] and i1 == i2: 
     d1, d2 = p1[1] - i1, p2[1] - i2 
     y = min(d1 + d2, (1-d1) + (1-d2)) 
     return abs(p1[0] - p2[0]) + y 

    # simple case, return the Manhattan distance 
    return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1]) 


print(minimum_distance([0.4, 1], [0.9, 3])) 
# 2.7 
+0

x'in bir noktada yüzdüğü ve diğerinin de basit taksiye indirgendiği durum hakkında iyi bir fikir. –

0

int ve float karışımı değil, muhtemelen kayan nokta hatasıyla karşılaşıyorsunuz. floats kesin değildir, yaklaşık değerlerdir ve bu nedenle küçük miktarlarda "kapalı" olabilirler.

decimal modülünün sağladığı Decimal nesnelerini, kayan nokta değerleriyle doğru şekilde çalışmak için kullanabilirsiniz. İşte bir örnek:

>>> 1.1 + 2.2  # will produce small error 
3.3000000000000003 
>>> from decimal import Decimal 
>>> Decimal('1.1') + Decimal('2.2') 
Decimal('3.3') 

nihai sonuç yine "kapalı" olacak, ama Decimal kullanılarak kümülatif yuvarlama hatalarını önlemek için yardımcı olacaktır: Farklı kombinasyonlar baktığınızda

>>> 3.3 - (1.1 + 2.2) 
-4.440892098500626e-16 
>>> Decimal(3.3) - (Decimal(1.1) + Decimal(2.2)) 
Decimal('-4.440892098500250464677810669E-16') 
>>> Decimal('3.3') - (Decimal('1.1') + Decimal('2.2')) 
Decimal('0.0') 
+0

Bir ya da iki noktadan fazla kapalı, bazen kapalı olarak söyleyin 0,2 - 0,6 – JonnyDoeInWisco

+0

@JonnyDoeInWisco: evet, her bir kayan nokta işlemi ile hata birikebilir. 'Decimal' nesnelerini kullanmak birikimli hataları azaltmalıdır. – mhawke

+0

@JonnyDoeInWisco Bu hata, tipik boyut girişi için büyükse şaşırırdım. Belki de sorunuzu düzenleyebilir ve oldukça küçük bir yuvarlama hatasıyla açıklanamayacağını düşündüğünüz herhangi bir hatanın örneğini görebilirsiniz. –

2

bir köşeye kısa menzilli taksiyi almak:

girişimi gibi görünebilir. Bunu yapmanın iki yolu var. Ardından, ortaya çıkan köşeler arasında uzun menzilli bir taksiler kullanın. Gezinilen köşelere bağlı olarak 2x2 = 4 olasılık vardır. min atın:

Örneğin
from math import ceil,floor 

#as a helper function, vanilla taxicab: 

def t(p,q): 
    x,y = p 
    z,w = q 
    return abs(x-z)+abs(y-w) 

#find the two corners closest to a point: 

def corners(p): 
    x,y = p 
    if isinstance(x,float): 
     return [(floor(x),y),(ceil(x),y)] 
    else: 
     return [(x,floor(y)), (x,ceil(y))] 

#combine these: 

def dist(p,q): 
    return min(t(p,c) + t(c,d) + t(d,q) for c in corners(p) for d in corners(q)) 

,

>>> dist((.4,1),(.9,3)) 
2.7 
+0

Çok temiz. Çok verimli değil, bu yüzden tekrar tekrar kullanılması gerekiyorsa, optimize etmeye değer olabilir. –

+0

Zamanlama ilginç olabilir. En az 3 vakaya ihtiyacınız olacak ne olursa olsun, tüm vakaları bulmaya ve min operatörün hangisini seçmesine izin vermeye karar verdim. Yerleşik operatörler C ile yazılmıştır, bu yüzden bu rotanın hangi durumda kullanılacağına açıkça karar vermekten daha yavaş olduğu net değildir. Benim yaklaşımımın zor vakalarda sizinkinden daha hızlı olduğunu sanıyorum, ama basit taksicab'a düştüğü kolay bir durumda kesinlikle sizinkinden daha yavaştır, bu yüzden net sonucun ne olduğunu söylemek zor. –

+0

Bazı basit testlerden, zor vakalarda işlevimin 4x daha hızlı olduğu ve kolay vakalar için daha hızlı olduğu görülüyor. Bu doğal görünüyor çünkü fonksiyonum sadece Manhattan mesafesini dört kez değil bir kez hesaplıyor. Üç vakanın dikkate alınması gerekirken, "ağır" hesaplamaları gerçekte yapmaksızın hızla ortadan kaldırılabilir. –

İlgili konular