Чи існує мова програмування, де 1/6 поводиться так само, як 1.0 / 6.0?


11

Поки я програвав на C ++ кілька днів тому, я допустив цю помилку (що в мене є історія її створення!). В одній частині свого коду я мав 1/6, і я очікував, що це буде 0.16666666666, що не так. Як ви всі знаєте, результат 0 - C, C ++, Java, Python, всі поводяться однаково.

Я розміщую це на своїй сторінці у Facebook, і зараз ведуться дискусії щодо того, чи є мова програмування, де 1/6поводиться так само, як 1.0/6.0.


5
Хаскелл. 1/6 = 0,16666666666666666
t123

PowerShell генерує 0,166666666666667, що мене здивувало, оскільки 1 є цілим числом. Я б ставку, що є деякі інші .NET мови, які генерують очікуване вами значення.
JohnL

Теоретично їх існує необмежена кількість .. Ось ще: Ребол , а також такі похідні, як Орка, Червоний тощо. >> 1 / 6->== 0.166666666666667
Ізката

Луа це робить. Він має лише один номер типу, який, як правило, є таким, як подвійний С.
Мачадо

У Clojure 1/6- це фактично 1/6 (дробовий тип), який, примусово Double, дорівнює 1.66666 ...
якD

Відповіді:


17

Чи всі забули Паскаля?

1/6врожайність 0.1666666...(до будь-якої точності підтримується).

1 div 6 врожайність 0

Сперечається, чи правило C є помилкою. Практично всі арифметичні оператори С, де операнди одного типу, дають результат того ж типу. Щось слід сказати для послідовності.

Крім того, оскільки C в основному орієнтований на код на системному рівні, більшість програм C взагалі не використовують плаваючу крапку. Свого часу випадкове додавання коду з плаваючою комою до програми, яка інакше не потребувала, може стати серйозною проблемою. Це, мабуть, все-таки так, і для малих вбудованих систем, які, знову ж таки, є головною ціллю для C.

У більшості програм C, обрізання цілого поділу - це, мабуть, саме те, що вам потрібно.

Якщо ви 1 / 6отримаєте результат з плаваючою комою в C, то:

  • Це було б невідповідність мови.
  • Стандарт повинен був зробити довільний вибір, який тип з плаваючою комою використовувати для результату ( doubleможе здатися природним вибором, але ви можете віддати перевагу додатковій точності long double)
  • Мова все ще повинна мати операцію для цілого поділу; виконання додавання з плаваючою комою, а потім обрізання, ймовірно, не буде досить гарним.

C міг би забезпечити окремі оператори для двох видів поділу, але другий пункт вище все-таки застосовуватиметься: який із трьох типів з плаваючою комою буде використаний для результату? А оскільки отримати ділення з плаваючою комою досить просто, якщо він вам потрібен (використовуйте константу з плаваючою комою для одного або обох операндів, або переведіть один або обидва операнди на тип з плаваючою комою), мабуть, це не було ' t вважав це важливим.

У версії посібника С 1974 року (це за 4 роки до виходу першого видання K&R) Рітчі навіть не згадує можливу плутанину:

Двійковий / оператор вказує на поділ. Застосовуються ті ж міркування типу, що й для множення

що говорить, що якщо обидва операнди типу intабо char, результат має тип int.

Так, це джерело плутанини для деяких програмістів на C, особливо для початківців - але C не відзначається тим, що він дуже сприятливий для початківців.


5
Паскаль. Отримання деталей безпосередньо перед тим, як C помилився з ними. ™
Мейсон Уілер

І тоді Алгол був вдосконаленням щодо своїх наступників (у кількості яких виступають і С, і Паскаль).
AProgrammer

Паскаль - уточнення реквізитів (дати або взяти коефіцієнт 10)
Мартін Бекетт

1
Я спочатку писав 1.666666..., що явно неправильно. Моє виправдання - це тестова програма Паскаля, яку я написав друкованою1.6666666666666667E-0001
Кіт Томпсон

16

Насправді така поведінка була змінена в Python 3, і тепер вона веде себе так, як ви очікували ( //зараз використовується для цілого поділу).


Дякую. Будь-які інші мови програмування ви пам’ятаєте? Базова сім'я, можливо?
Пуя

1
@Pouya: Така поведінка є стандартною для родини Паскалів. /завжди створює значення з плаваючою комою, а окремий оператор ( div) використовується для цілого поділу.
Мейсон Уілер

13

З видатних мов, JavaScript. 1,0 / 6,0 = 1/6 = 0,16666666666666666.

Я не вважаю це дивним. Як правило, якщо мова розрізняє цілі числа та числові типи з плаваючою комою, розділення двох цілих чисел дасть усічене ціле число замість float. Якщо цього не відбудеться, швидше за все, це буде типово для операцій з плаваючою комою. Це має бути очікуваною поведінкою з боку програміста.

Пам’ятайте лише про те, що тут можуть бути відтворені додаткові речі, як уже згаданий оператор розділеного цілого поділу чи неявний тип кастингу.


6
Це не "велике правило". Це правило C і кілька мов, які сліпо копіюють помилки C.
Мейсон Уілер

4
@MasonWheeler: Чи FORTRAN "наосліп копіював помилку C"? Я особисто вважаю, що добре розроблені мови повинні використовувати окремі оператори для усіченого поділу проти приблизного поділу цілих чисел (а також, btw, для значення та референтної рівності), але рішення проекту в дні FORTRAN, ймовірно, було розумним. Це не означає, що кожна мова повинна робити так, як це робив FORTRAN у 1950-х.
supercat

3
Ці мови мають розрізняти мови нижчого рівня. Мови вищого рівня / динаміки часто краще обійтися без них. Це компромісний дизайн. Я вдячний лише тим, що в JS є один великий конструктор / тип "німий", але я думаю, що відчував б, що JS бракує при спробі написати високоефективний 3D-двигун без жорсткого управління типом. JS може мати корисну програму з іншими мовами, але я не думаю, що ніхто ніколи не буде вважати це гото для написання високопродуктивних матеріалів, ближчих до хрому.
Ерік Reppen

2
Математика поза програмуванням враховує цілі правила для поділу.
Ерік Реппен

5
@MasonWheeler: Програмування не є чистою математикою. Математично 1/6 є раціональним числом і не може бути точно представлене двійковим числом з плаваючою комою. Єдине точне подання - це співвідношення зі знаменником у шість разів більшим числом.
кевін клайн

7

Є багато мов, де ((1/6)*6)результати в 1, а не в 0. Наприклад, PL / SQL, безліч діалектів BASIC, Lua.

Випадково в усіх цих мовах 1/6 призводить до .166666667, або 0.16666666666667 або чогось подібного. Я вибрав варіант ((1/6) * 6) == 1, щоб позбутися цих маленьких відмінностей.


7
Це не питання.
Roc Martí

20
Випадково в усіх цих мовах 1/6 призводить до .166666667, або 0.16666666666667 чи чогось подібного. Я вибрав ((1/6)*6)==1варіант, щоб позбутися тих маленьких відмінностей, але, схоже, я переоцінив математичні навички деяких людей.
користувач281377

1
@ RocMartí так, це дійсно так ...
MattDavey

1
Я був би здивований, побачивши, що (1.0 / 6.0) * 6 рівно рівний 1! Округлення результату (1,0 / 6,0) призведе до невеликої різниці. (Хоча для нескінченної точності буде кілька мов, яким за замовчуванням є нескінченна точність)
Sjoerd

1
@Sjoerd: Насправді це не надто перенапруження. Розглянемо у десятковій частині сценарій 1/11 * 11 з усіма значеннями точними до п’яти значущих цифр. Значення 1/11 становить 9,0909 * 10 ^ -2. Помножте на 11 і один отримав би 99,9999 * 10 / -2 перед округленням. Закруглете до п’яти значущих цифр і результат становитиме 1.0000 * 10 ^ 0. Зауважимо, що ключовим є те, що мантіса 1/6 - це "... 0101010101 ...". Якщо останнім бітом представлення є "1", помноживши його на шість і округлення дасть 1. Якби останній біт був нульовим, він би не став.
supercat

3

Haskell розглядає 1/6 та 1.0 / 6.0 як однакові 0,1666666666666666666. Крім того, він відображає 1 / 6,0 і 1,0 / 6, як те саме значення.

Це пояснюється тим, що основні числові типи в Haskell не зовсім такі, як в інших мовах. Справжнє ціле ділення дещо ... складне.


2

Так, Perl. Однолінійний

perl -e '$x=1/6;print "$x\n";'

призводить до виходу:

0.166666666666667

Я вважаю, що PHP працює так само.

Відредаговано, щоб додати: Я також вважаю, що необхідною (але недостатньою) умовою 1/6 == 1.0/6.0є мова, про яку йде мова, слабо набраною.


Чому б чортові було б слабко вводити текст (що б це означало)? Просто визначте / до (також) середній роздільний похід у випадку, якщо обидва аргументи є цілими числами.

1
@delnan - en.wikipedia.org/wiki/Weak_typing я вважаю , можна було б мати строго типізований мову , на якому /автоматично перевантажений в залежності від типів аргументів, але здається , що як порушення принципу найменшої Подиву до я ...

2
Слабке / сильне введення тексту невірно (як вікі також передбачає), будь ласка, уникайте цього та будьте конкретні. Я вважаю, що ваше визначення забороняє неявну конверсію, але не спеціальний поліморфізм? Якщо так, то розглянемо Хаскелл, який не має неявних перетворень, але досить добре виконаний (як у, працює 99% часу і може бути зрозумілий смертними) числовий поліморфізм. І чому це було б дивним? Було б набагато дивніше (не кажучи прикро) для мене, якби мені довелося додати кілька точок у кожен окремий екземпляр будь-якого оператора, залежно від точної точності, яку я бажаю.

2
@JackManey Я думаю, що для більшості новачків набагато дивніше, що 1/2 має дорівнювати 0, ніж це, якщо ділення двох цілих чисел призводить до подвійного. Зрештою, цілі числа також не закриті під діленням в математиці. Крім того, як вказує делнан, Haskell є прикладом сильно набраної мови, в якій / на двох цілих числах не утворюється ціле число. А Python 3 - це інше.
sepp2k

1
Мова Haxe сильно (хоч і робиться висновком) набрана, і все ж вона не має цілого поділу, лише плаваюча. Так що ви йдете.
K.Steff

2

У Squeak Smalltalk /на цілі числа створює об'єкти Дробу. Отже, хоча це не те саме, що поділ поплавця, все одно (1/6)*6повертає 1.


У всіх похідних Smalltalk-80 (тобто майже у всіх Smalltalk). Бурштин - це одне із сучасних винятків (що зрозуміло, збирається на JavaScript).
herby

2

Так, я щойно перевірив вбудований TI-99 / 4A в TI BASIC . Оскільки вона розглядає всі числові вирази як плаваючу точку, операція ділення є також плаваючою точкою.

 TI BASIC READY
>PRINT 1/6
  .1666666667

>


2

MATLAB. Числові літерали за замовчуванням є подвійними.

>> 1/6
ans =
    0.1667

2

Clojure використовує дроби за замовчуванням. Це не те саме, що 1,0 / 6,0, але ви можете конвертувати в нього за допомогою floatабо doubleколи вам потрібно.

user=> (/ 1 6)
1/6
user=> (* (/ 1 6) 2)
1/3
user=> (pos? (/ 1 6)) ; Is 1/6 > 0?
true
user=> (float (/ 1 6))
0.16666667

1

Дивно, але здається, що він працює належним чином у Windows PowerShell (версія 3) .

PS C:\> 1.0 / 6.0
0.166666666666667

PS C:\> 1/6
0.166666666666667

Також, здається, працює в Python 3, як згадується sepp2k. Інші дві мови, які я легко доступний для REPL, Scala та Ruby, обидві мають цілочисельний поділ та вихід 0.


0

Мова Rexx завжди створює арифметично правильну відповідь. Наприклад: 5/2 = 2,5. Rexx - чудова мова, яка недостатньо використовується. Теоретично, коли компілятор не може визначити, що ви хочете, краще зробити правильну математику, однак це може бути неефективно. Rexx також надає // оператора.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.