วิธี“ ในขณะที่ (i == i);” เป็นวนรอบไม่สิ้นสุดในแอปพลิเคชันเธรดเดียวหรือไม่


141

ฉันเพิ่งมีคำถามที่ฉันไม่สามารถตอบได้

สมมติว่าคุณมีนิยามลูปนี้ใน Java:

while (i == i) ;

ชนิดของiและค่าของiถ้าลูปไม่ใช่ลูปไม่สิ้นสุดและโปรแกรมใช้เธรดเดียวเท่านั้น ?


7
โอ้เพื่อประโยชน์ของพระเจ้าผู้คนจะได้รับเกียรติที่จะแสดงความคิดเห็นว่าทำไมพวกเขา downvote? สิ่งนี้ถูกแท็กเป็นปริศนาว่ามีปัญหาอะไร ???
user54579

10
ฉันคิดว่าบางคนไม่สามารถหยุดการลงคะแนนเพื่ออะไรก็ได้
FerranB

1
Bah, ขอโทษที่ทำให้สิ่งนี้: / ฉันเพียงแค่ต้องการคำตอบและฉันไม่สามารถแก้ไขได้ด้วยตัวเอง
Zizzencs

1
@ Nickolai นั่นคือธรรมชาติของ SO - การ downvoting โดยการขับรถเป็นความจริงที่น่าเสียดายและมีการพูดคุยและปฏิเสธความคิดเห็น แต่ดูเหมือนว่า "ชุมชน" เป็นที่โปรดปรานของคำถามนี้หลังจากทั้งหมด
paxdiablo

1
หนึ่งในเทคนิคของคำถามประเภทนี้คือผู้คนคิดว่าชื่อตัวแปรบางตัวเช่น i คือ int, d คือ double, s คือสตริงหรือสั้น ๆ , ch คือ char, l คือยาว, b สำหรับ ไบต์หรือบูลีน คุณต้องถามตัวเองว่าประเภทใดที่แนะนำและเป็นไปได้
ปีเตอร์ Lawrey

คำตอบ:


125
double i = Double.NaN;

API สำหรับDouble.equals ()สะกดคำตอบ: "Double.NaN == Double.NaN มีค่า false" มีการอธิบายอย่างละเอียดในข้อกำหนดภาษา Java ภายใต้ " ประเภทจุดลอยตัวรูปแบบและค่า ":

NaNคือเรียงลำดับดังนั้นการดำเนินการเปรียบเทียบตัวเลข<, <=, >และ>= ผลตอบแทนถ้าอย่างใดอย่างหนึ่งหรือทั้งสองตัวถูกดำเนินการอยู่false NaNผู้ประกอบการไม่เท่าเทียมกันที่==ผลตอบแทนfalseถ้าทั้งตัวถูกดำเนินการเป็นNaNและผู้ประกอบการอสมการ!=ผลตอบแทนถ้าทั้งตัวถูกดำเนินการคือtrue โดยเฉพาะอย่างยิ่งคือถ้าหากมีและจะเป็นถ้าหรือเป็นNaNx!=xtruexNaN(x<y) == !(x>=y)falsexyNaN


1
โอ้ดังนั้นคุณสามารถทำ "ไม่ใช่ตัวเลข"!
Filip Ekberg

12
มันมีความแข็งแกร่งทางคณิตศาสตร์ทำไมจำนวนที่ไม่จริงควรจะเท่ากัน? 5/0! = sqrt (-4)
Gordon Gustafson

2
@CrazyJugglerDrummer: บางที แต่ในทำนองเดียวกันx == xควรเป็นจริงเสมอ ทำไมไม่มีอะไรที่ไม่เท่าเทียมกัน?
Bart van Heukelom

1
บาร์ต: เพราะจริงๆแล้วไม่รู้จักไม่เท่ากับเสมอไม่ทราบ บางครั้งก็จะเป็นประโยชน์ที่ว่าทำไมฐานข้อมูลมีโมฆะ ...
Konerak

2
@inovaovao: ไม่ในฐานข้อมูลnull=nullเป็นโมฆะ NULL IS NULLคือ 1.
Konerak

29

ค่าของiนั้นไม่ถูกต้อง "ไม่ใช่ตัวเลข"

หลังจาก googling ฉันพบว่าคุณสามารถมี NaN (ไม่ใช่ตัวเลข) ใน Java! ดังนั้นจำนวนจุดลอยตัวคือชนิดข้อมูลและค่าคือ NaN ดูที่นี่


12
ใช่นั่นแหล่ะ ค่าของ i คือ Jon Skeet
Andrew Rollings

ฉันมักจะเกลียดคนที่ downvote โดยไม่มีเหตุผล ... ฉันเป็นคนแรกที่พูดว่า "ไม่ใช่ตัวเลข" แต่ไม่คิดว่าจาวาสามารถจัดการกับมันได้เพราะมันไม่ได้จัดการอะไรที่ยอดเยี่ยม
Filip Ekberg



8

ฉันไม่แน่ใจ แต่ฉันเชื่อว่า (i == i) ไม่ใช่การดำเนินการปรมาณูในกระบวนการมัลติเธรดดังนั้นหากค่า i จะถูกเปลี่ยนโดยเธรดอื่น ๆ ระหว่างการกดของค่ามันเพื่อสแต็กในเธรดที่ดำเนินการลูปแล้วเงื่อนไขนั้นสามารถ เป็นเท็จ


8

เนื่องจากคนอื่น ๆ บอกว่าเป็น NaN ฉันอยากรู้เกี่ยวกับการใช้งานอย่างเป็นทางการ (JDK 6) Double.isNaNและเห็นว่า:

/**
 * Returns <code>true</code> if the specified number is a
 * Not-a-Number (NaN) value, <code>false</code> otherwise.
 *
 * @param   v   the value to be tested.
 * @return  <code>true</code> if the value of the argument is NaN;
 *          <code>false</code> otherwise.
 */
static public boolean isNaN(double v) {
    return (v != v);
}

2

คิดว่าน่านเป็นข้อยกเว้น แต่ใช้ค่าเวทย์มนตร์ภายในการคำนวณ เนื่องจากการคำนวณล้มเหลว - เช่นรากที่สองของค่าลบ, หารด้วยศูนย์ ฯลฯ - มันไม่มีเหตุผลที่จะเปรียบเทียบมันกับสิ่งอื่นใด ท้ายที่สุดถ้าหารด้วยศูนย์มันจะเท่ากับน่านรากที่สองของ -2 หรือรากที่สองของ -3?

น่านช่วยให้การคำนวณที่มีขั้นตอนที่ส่งกลับคำตอบที่ไม่ถูกต้องให้เสร็จสมบูรณ์โดยไม่ต้องมีข้อยกเว้นพิเศษ ในการตรวจสอบว่าคำตอบคือค่าเพียงแค่ทดสอบว่าไม่ใช่ความจริง (คือคำว่าไม่ใช่ถ้าฉันใส่ไว้) ผ่านทาง Float.isNan () o ที่เทียบเท่ากัน


3
มันจะง่ายกว่าที่จะคิดว่ามันเป็นยกเว้นออลิออต แต่ถ้าฉันรู้จริง ๆ ว่าออดิโอลุตคืออะไร :-)
paxdiablo

2

ฉันจะเพิ่ม

float i = Float.NaN;

เช่นกัน

double i = Double.NaN;

เคล็ดลับทั่วไปในคำถามประเภทนี้ในสมมุติฐานที่คุณทำให้ฉันเป็นคนโง่ ข้อสันนิษฐานทั่วไปอื่น ๆ อาจเป็น s คือ String, x, y เป็นสองเท่า, ch คือ char, b เป็นไบต์เป็นต้นหากคุณเห็นคำถามเช่นนี้คุณสามารถเดิมพันได้ว่า 'i' ไม่ใช่ประเภทที่คาดหวัง

คำถามที่คล้ายกันคือ; สิ่งนี้ไม่เคยลูป 'x' คืออะไร

while(x == x && x != x + 0) { }

อีกคำถามที่ฉันชอบคือ; ลูปนี้เป็นลูปไม่สิ้นสุดสิ่งที่เป็นไปได้ของค่า x (: ฉันนับพวกเขาสิบสองคน :)

while(x != 0 && x == -x) { }

0

ฉันรู้ว่านี่เป็นคำถามเกี่ยวกับ Java แต่การพิจารณาคำถามสำหรับภาษาอื่นนั้นน่าสนใจ

ใน C ประเภทง่ายๆเช่น 'int' สามารถแสดง 'ยุติก่อนที่เอกภพจะเย็นลง' ถ้า 'i' ถูกประกาศว่าเป็นสารระเหย (ดังนั้นคอมไพเลอร์จะถูกบังคับให้อ่าน 'i' สองครั้งต่อการทำซ้ำ) และถ้า 'i' อยู่ในความทรงจำจริงๆ จากนั้นลูปจะยุติลงเมื่อ 'i' เปลี่ยนไประหว่างการอ่านซ้ำสองครั้งของการวนซ้ำสองครั้ง ( เพิ่ม : สถานที่ที่เป็นไปได้ - ในไมโครคอมพิวเตอร์ที่ 'i' ตั้งอยู่จริงตามที่อยู่ของพอร์ต I / O อาจเชื่อมต่อกับเซ็นเซอร์ตำแหน่งอาจเป็นไปได้มากขึ้นถ้า 'i' เป็นตัวแปรตัวชี้ ( ตัวชี้ไปยังหน่วยความจำระเหย) และคำสั่งคือ ' while (*i == *i);')

ดังที่เห็นได้จากคำตอบอื่น ๆ ใน C ++ ผู้ใช้สามารถระบุโอเปอเรเตอร์ '==' ได้หากฉันเป็นคลาสที่ผู้ใช้กำหนดดังนั้นอาจมีอะไรก็ได้ที่เป็นไปได้

ค่อนข้างเหมือน NaN ในภาษาที่ใช้ SQL ลูปจะไม่สิ้นสุดหากค่าของ i เป็น NULL; อย่างไรก็ตามค่าที่ไม่ใช่ค่า NULL จะทำให้วนซ้ำไม่สิ้นสุด นี่เป็นเหมือน Java ซึ่งจำนวนใด ๆ (ตรงข้ามกับ NaN) ทำให้วนรอบไม่สิ้นสุด

ฉันไม่เห็นสิ่งก่อสร้างที่ใช้งานได้จริง แต่เป็นคำถามที่น่าสนใจ


0

ฉันประหลาดใจที่ไม่เห็นโซลูชันนี้:

while (sin(x) == sin(x)) //probably won't eval to true

ในการตอบกลับความคิดเห็นลองใช้สิ่งนี้:

double x = 10.5f;
assert (x == asin(sin(x)));

x ควรเท่ากับ arcsine (sin (x)) ในทางทฤษฎีเสมอ แต่ในทางปฏิบัติมันไม่ได้


3
ทำไมจะไม่ล่ะ? คุณกำลังทำการคำนวณเดียวกันกับข้อมูลเดียวกันทุกประการผลลัพธ์ทั้งสองจะมีข้อผิดพลาดเดียวกันทั้งหมด
Loren Pechtel

ฉันจำไม่ได้ว่าฉันอ่านตรงไหน แต่ขึ้นอยู่กับเครื่องจักร / การนำไปใช้ของคุณ Sin (x) ในการเรียกฟังก์ชั่นหนึ่งมีโอกาสน้อยมากที่จะเท่ากับ sin (x) ของการโทรที่แตกต่างกัน มันเกี่ยวข้องกับความถูกต้องของตัวเลขจุดลอยตัว (สิ่งที่พิเศษเกี่ยวกับฟังก์ชั่นตรีโกณฯ ที่ทำให้พวกเขาไม่คืนค่าเดิมสองครั้ง)
jkeys

ดูการปรับปรุงของฉัน Arcsine "เลิกทำ" บาปของ x ดังนั้นพวกเขาควรจะเท่ากัน แต่พวกเขาไม่ใช่
jkeys

นั่นไม่ใช่สิ่งเดียวกัน เช่นเดียวกับ Loren ที่กล่าวว่าคุณกำลังทำการดำเนินการเดียวกันอย่างแน่นอนในวันxที่ซึ่งควรให้ผลลัพธ์ที่เหมือนกันแน่นอนโดยมีความไม่ถูกต้องเหมือนกัน Arcsin ไม่สามารถย้อนกลับผลลัพธ์ของความบาปด้วยจำนวนจุดลอยตัวเนื่องจากค่าที่ส่งผ่านไปasin()นั้นจะไม่แม่นยำอย่างแน่นอน ดังนั้นผลลัพธ์ของการasin()จะไม่ถูกต้องทำให้x == asin(sin(x))เป็นเท็จ นอกจากนี้ arcsin ไม่จำเป็นต้อง "เลิกทำ" การดำเนินการบาป - ฟังก์ชัน sin สามารถให้ผลลัพธ์เดียวกันสำหรับค่าหลายค่าของ x ซึ่งเป็นเหตุผลว่าทำไมasin()ส่งกลับตัวเลขระหว่าง-π / 2 ถึงπ / 2 เท่านั้น
hbw

2
กล่าวอีกนัยหนึ่ง arcsin ไม่สามารถ "เลิกทำ" ฟังก์ชันการทำบาปได้เสมอไปเพราะ arcsin ไม่สามารถรู้ได้ว่ามุมเดิมคืออะไร ตัวอย่างเช่นบาปของทั้งπ / 2 และ5π / 2 ให้ 1 แต่อาร์ซีซิน (1) คืออะไร? เห็นได้ชัดว่าไม่สามารถให้ทั้งสองกลับมาใช่มั้ย ดังนั้นผลลัพธ์ของ arcsin จะต้องถูก จำกัด ให้อยู่ในช่วงเรเดียน 2 meaning ซึ่งหมายความว่ามันไม่สามารถยกเลิกผลลัพธ์ของฟังก์ชันบาปได้จริงนอกเสียจากว่ามุมดั้งเดิมจะอยู่ระหว่าง 0 ถึง2πหรือในกรณีของ C, -π / 2 และ π / 2 (อันที่จริงอาร์ซีซิน (บาป (5π / 2)) = π / 2) อย่างไรก็ตามนั่นเป็นคำอธิบายที่ยาวมาก ๆ แต่ฉันหวังว่าจะช่วยให้เข้าใจผิด ๆ ได้
hbw

0

ไม่ใช่วงวนไม่สิ้นสุดหนึ่งกระทู้ :)

import static B.*;
public class A {
    public static void main(String[] args) {
        System.out.println("Still Running");
        while (i == i) ;
    }
}


public class B {

    public static int i;
    static {
        System.exit(0);
    }
}

-1

i == iไม่ใช่อะตอม พิสูจน์แล้วโดยโปรแกรมดังกล่าว:

static volatile boolean i = true;
public static void main(String[] args) throws InterruptedException
{
    new Thread() {
        @Override
        public void run() {
            while (true) {
                i = !i;
            }
        }
    }.start();

    while (i == i) ;
    System.out.println("Not atomic! i: " + i);
}

อัปเดตที่ นี่เป็นอีกตัวอย่างหนึ่งของการวนซ้ำแบบไม่สิ้นสุด (ไม่มีการสร้างเธรดใหม่)

public class NoNewThreads {
    public static void main(String[] args) {
        new NoNewThreads();
        System.gc();
        int i = 500;
        System.out.println("Still Running");
        while (i == i) ;
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        Thread.sleep(1000);
        System.exit(0);
    }
}

@Charles Goodwin สิ่งที่คุณพูดถึงความจริงที่ว่าไม่มีความเป็นไปได้ที่จะเขียนโปรแกรม Java โดยใช้หนึ่งเธรด :) ดังนั้นโซลูชันอื่น ๆ จึงใช้อย่างน้อยสองเธรด (เหมือนกับโปรแกรมที่สองของฉันในส่วน 'อัพเดต')
Andrey

นั่นไม่ใช่การเบรกลูป รหัสใด ๆ หลังจากที่while (i == i);เคยชินรัน
aalku

จบการใช้หัวข้ออื่น แต่มันเป็นสิ่งที่ดีที่จะชี้ให้เห็น มันเป็นเหตุผลที่คำถามเดิมกล่าวว่า "และโปรแกรมใช้เพียงหนึ่งเธรด" .. ชนิดของการระบุอย่างชัดเจนว่านี่คือคำตอบที่ชัดเจนและพวกเขาต้องการให้คุณดูเพิ่มเติม
Bill K
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.