5ちゃんねる ★スマホ版★ ■掲示板に戻る■ 全部 1- 最新50  

■ このスレッドは過去ログ倉庫に格納されています

トリッキーなコード

1 ::2001/02/26(月) 21:51
独りよがりのためのスレッド
大体トリッキーなコードを書く奴に限って
致命的なバグを出したりするんだけど、
書きたいもんはしょうがない。

479 :475:2001/07/16(月) 15:20
本体その2
/************************************************************************/
/* タスクのスタート */
/************************************************************************/
void
_sta_tsk()
{
alloca( --crntid ? tasklist[crntid].size : 1024);
if( crntid > 0 ){
//crntid -= 1;
tasklist[crntid].name();
}else{
crntid = 1;
longjmp( tasklist[1].buf,2 ); /* タスクの起動 */
}
}
/************************************************************************/
/* タスクスイッチャ */
/************************************************************************/
void
_wai_tsk()
{
if( setjmp( tasklist[crntid].buf ) ){
return;
}else if( tasklist[crntid].flg ) {
longjmp( tasklist[0].buf, crntid );
}
tasklist[crntid].flg = 1;
_sta_tsk();
}

480 :475:2001/07/16(月) 15:21
使用例。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <setjmp.h>
#include "rt.h"
int main( void );
void task1( void );
void task2( void );
void pr( int, int, char* );

main()
{
if( _cre_tsk( task1, 0x700 ) );
if( _cre_tsk( task2, 0x700 ) );
/* 開始ルーチン */
_sta_tsk();
return( 0 );
}
void
task1( void )
{
int i=0;
char work[10];
for(;;){
sprintf( work,"%d", i-- );
pr( 5,10,work );
_wai_tsk();
}
}
void
task2( void )
{
int i=0;
char work[10];
for(;;){
sprintf( work,"%d", i++ );
pr( 25,10,work );
_wai_tsk();
}
}

void pr( int x, int y, char *str ){
printf( "\x01b""[%d;%dH""\x01b""[0K%s" , y+1, x+1, str );
}

481 :デフォルトの名無しさん:2001/07/18(水) 16:41
a += b -= (a = b-a);
加減算でのスワップってがいしゅつ?
&a=&bだとだめだけど・・

482 :デフォルトの名無しさん:2001/07/18(水) 21:55
>>474
必要ってわけじゃないけど、所有関係や参照関係すらない object を
数え上げることができるのがコード書くときに楽。あんまりトリッキー
じゃないのでスレ違いっぽいのは確か(可読性も高いよね)。

 例えばドキュメント、ページ、その中の画像オブジェクト、というような
階層状の構造をもつ何かを編集するソフトで、特定の画像ファイルの消去等
の際には、ドキュメント→ページ→画像オブジェクト、アンドゥバッファ中
の画像オブジェクト、クリップボード上の画像オブジェクト、などいろんな
ところを見なくちゃならないでしょ。そういうときに「全ての画像オブジェ
クト」ってのを用意して手抜きするわけです。

483 :デフォルトの名無しさん:2001/07/20(金) 01:15
>>481
a ^= b ^= ( a ^= b ) ;
整数型のスワップならこうだろう。
って、昔はアセンブラなんかでは良く使った手だな…。

484 :デフォルトの名無しさん:2001/07/20(金) 23:44
>>483
アセンブラなら直接交換する命令を使ったが。
そんなのもないやつ?

485 :デフォルトの名無しさん:2001/07/20(金) 23:48
>>484
レジスタペアには使えなかったりとか。

486 :481:2001/07/21(土) 13:05
>>483
>>2で超がいしゅつ

487 :デフォルトの名無しさん:2001/07/21(土) 13:56
32bit signed int -> 16bit signed int に飽和させながら
変換するのでトリッキーというか、分岐を起こさせずにやる
方法ありませんか(Cで)。

488 :デフォルトの名無しさん:2001/07/21(土) 14:46
>>487
符号無しなら簡単だけどねえ
原理としては最初に16bit左シフトして、
あちこちシフトしながら or 繰り返せば
0か オール1になるから、 ORすればクリップ出来る

符号付きで同じ方式を使うとすると、 17+15に分けて
上位17bitがオールゼロか オール1なら 0に
 でなければ MSBによって $7fffか$FFFFを作って
  OR するという事で

シフトと論理演算だけで出来ない訳じゃないけど厳しいねえ

489 :デフォルトの名無しさん:2001/07/21(土) 14:47
×最初に16bit左シフト
○最初に16bit右シフト

490 :488:2001/07/21(土) 15:18
全然ダメ 488 は間違いね 恥ずかしい・・・

491 :デフォルトの名無しさん:2001/07/21(土) 15:23
>>487
どういうことだかわからないんだけど、こうしたいっていう具体例を
挙げてもらえる?

492 :488:2001/07/21(土) 15:32
アセンブラなら出来た Cでも書けない事はないけど
short clip16(int x)
{
short c;
_asm {
 mov eax,x ;
 cdq ;//edxに符号拡張して
 sar eax,15 ;//桁溢れがあるかどうか
 xor eax,edx;
 add ax,0ffffh;
 mov ax,0 ;//
 adc ax,-1 ;//桁溢れがあれば0 でなければ-1
 not ax
 xor dx,0x7fff;//8000か7fffか
 xor dx,word ptr x
 and dx,ax
 xor dx,word ptr x
 mov c,dx
 };
return c;
}

493 :488:2001/07/21(土) 15:36
ええと課題は
short clip16(int x)
{
 if(x> 0x7fff) return 0x7fff;
 if(x<-0x7fff) return -0x8000;
reutnr x;
}
を 分岐を使わず書け なんだと思うのだが

494 :デフォルトの名無しさん:2001/07/21(土) 15:39
>>487
 491 さんの言う通り、いまいちわからんのぉ。
Cレベルで分岐しない・・・って事じゃないよね?
そうするとターゲットプロセッサとコンパイラ依存
の問題だから、環境書かないとダメですぞ。
たとえばこの問題、ARM とかならCで分岐使ってても、
コンパイル後は分岐無しになったりするし。

汎用的な答えとして、
・テーブル引く
ってのはあるけどね

495 :デフォルトの名無しさん:2001/07/21(土) 15:41
分岐なしか。
if文なし、ならできるけど・・・

496 :デフォルトの名無しさん:2001/07/21(土) 15:53
result=(short)((h&0x7fff)|(h>>30)|(((h&0x7fffffff)<0x7fff)*0x7fff));
こんな感じ?検算してないけど。
条件文入ってるからダメか。

497 :496:2001/07/21(土) 15:54
result=(short)((h&0x7fff)|(h>>30)|(((h&0x7fffffff)>0x7fff)*0x7fff));
の間違いでした

498 :494:2001/07/21(土) 15:58
>>496,497
内容の確認はしてないけど、その手なら MIPS でも分岐命令は
出なさそう。

出題者の意図次第ですが、>>492 さんの解答がいいところを突いて
る予感はします。これも内容確認してませんが(w

499 :デフォルトの名無しさん:2001/07/21(土) 16:07
>>498
492はちっとなげーし、なによりインラインアセンブラは歓迎されねーだろ

500 :488:2001/07/21(土) 16:55
じゃ、同じ方式で、 途中、0なら0 でなければ -1 の部分が綺麗じゃないけど
short clip163(int x)
{
 int f=x>>31;
 int w=( f ^ x )>>15;
 w|=w<<16; w|=w>>8; w|=w>>4; w|=w>>2; w|=w>>1;
 return (short)( ( ( (f^0x7fff)^x) & w) ^ x);
}

>>497 は残念だけど負数の時にうまくゆかないよ

絶対値はabsマクロが分岐無しに展開してくれるから
absは有りだよね

501 :497:2001/07/21(土) 17:08
>>500
わりい。ちょっと直す。
result=(short)((h&0x7fff)|((h>>31)<<15)|(((h&0x7fffffff)>0x7fff)*0x7fff));
これでだいじょぶかな?

502 :488:2001/07/21(土) 17:19
確かに条件判断 >0x7fff は分岐に展開されないから 利用せて貰うと

これが c でもアセンブラ並なコードが出た
return (short)( ( ( ( (x>>31) ^ 0x7fff)^x)
           & (-( abs(x) > 0x7fff)) )
        ^ x);


>>501 まだダメ 負数だとオーバー時 -1 になってしまうよ
クリップだから -$8000 にならないと

503 :497:2001/07/21(土) 17:24
>>502
あはは。寝ぼけてた。ごめん。・・・旅に出ます。

504 :488:2001/07/21(土) 17:38
a xor b and c xor b
は cが1なら a xor b xor b = a cが0なら b

という事でビット毎の代入パターン

( (x>>31) ^ 0x7fff は 0x7fff+(x<0)

505 :494:2001/07/21(土) 17:43
>>499

じゃあ自分で、ってんで作ってみたぞ。
int clip (int a)
{
unsigned int b, res;

b = a + (a & 0x8000);
b = ((b >> 15) - 1) >> 31; // 0:over 1:not over
b ^= 1; // 1:over 0:not over
res = a | -b; // over なら 0xffffffff
res += (b << 15); // over なら 0x8000 加算 -> 0x00007fff
res ^= -(a >> 31 & b); // 元が負でoverなら 0xffffffff で xor -> 0xffff8000

return (int)res;
}

これも、もちろん内容の確認はしていない(w
くどい様だけど、条件次第だからねぇ。
abs がどう展開されるかもコンパイラ&プロセッサ次第。

たぶん、「算術&論理演算だけで片付ける」ってのが、
出題者の意図だとは思うが。

506 :488:2001/07/21(土) 18:01
たぶん、CPUがx86系で 条件判断が入ると遅いという事じゃないのかな?

それとも命令数を数えてコーデングしてて、分岐が入るとメンドクサイから
嫌だとか


条件によって代入とか 条件によって次命令スキップなんて
命令を備えてるCPUも多いんだけどね。

507 :487:2001/07/21(土) 18:38
スマソ
x86系でPCMのクリッピングに使います。

たしかにアセンブラレベルじゃMMXやcmovcc使えばいいし、
Cコンパイラでもgccとかは自動的にcmovcc使ってくれるのでよいのだが。

それとはちょっと別に「分岐を起こさせずに」ってのは、実質的な
意味よりも、>>505 の言うように「算術&論理演算だけで片付ける」
ってのでの方法をちょっと知ってみたかっただけなので・・・。

508 :デフォルトの名無しさん:2001/07/21(土) 18:45
せっかくだからガンガントリッキーに攻めようぜ

509 :デフォルトの名無しさん:2001/07/21(土) 19:18
今の所 >>502
(short) ( ( ( ( (x>>31) ^ 0x7fff)^x ) & (-( abs(x) > 0x7fff)) ) ^ x)

これが一番綺麗だね

510 :デフォルトの名無しさん:2001/07/21(土) 19:30
でも >>502のコードは条件が入ってて
 こいつが setcc al に展開される
 その後 eaxを使うと パーシャルレジスタストール に引っかからないのかな?

まあパーシャルレジスタストールなんて数年したら
そんな事もあったなあなんてレベルの話なんだろうけど

511 :デフォルトの名無しさん:2001/07/21(土) 19:37
速度はこのスレじゃ関係ないでしょ
 いかにトリッキーかのスレなんだから

512 :デフォルトの名無しさん:2001/07/21(土) 19:41
>>511
いや、いかにトリッキーかというのはあとから付いてくるものだよ。
なんつーか、「こんな方法があったのか!」っていうヒザポンな
解法をみんなで思いつくのが本来の趣旨 のような。
わき道にずれてごめんsage

513 :デフォルトの名無しさん:2001/07/21(土) 19:53
abs はだいたいマクロによって
1) 符号によって -1を作って
2)  1)  XOR 元の値
3   2)−1)
の3命令に展開されるよね

CMOVccのような条件転送 があれば
1) 負数にして
2) 符号が負数なら元を代入
って2ステップで出来るけど

514 :デフォルトの名無しさん:2001/07/21(土) 20:08
こういう事かな

unsigned iabs(int a)
{ int f=a>>31;
 return (a^f)-f;
}

だとすると -fが無くても1しか違わないから >>509
int f= (x>>31);
(short) ( ( ( ( 0x7fff-f ) ^ x ) & (-( ( x ^f ) > 0x7fff)) ) ^ x)

515 :デフォルトの名無しさん:2001/07/21(土) 20:44
せめてこういうふうに書いて欲しいな

//Selectの各bitが 1なら aを 選択 0 なら bを ビット単位に 選択
#define BitMask(a,b,Select) ( ( (a ^ b) & Select) ^b)

(short) BitMask( 0x7fff-f , x , -( ( x ^f ) > 0x7fff ) )

516 :デフォルトの名無しさん:2001/07/21(土) 21:02
/* ぽりんきーなコード */
if(a*a+b*b==c*c) printf("三角形の秘密はね、");

517 :デフォルトの名無しさん:2001/07/21(土) 21:10
フェルマーの定理でも証明するつもりか? >>516

518 :487:2001/07/21(土) 22:19
PCMのクリッピングなんで、+32767〜-32768からはずれた、
あまり大きな数値や小さな数値は絶対に入ってこないので、
数値を最初に32768を足して、unsigned int 32->unsigned int 16 の
飽和変換を行ってからまた 32768 を引こうかと思ったんだけど
unsigned int 32->unsigned int 16 の飽和はどうしようか・・・
教えて君ですまんそ

519 :487:2001/07/21(土) 22:20
あ、なんでもないです518は忘れてください

520 :デフォルトの名無しさん:2001/07/21(土) 22:47
一応、条件演算子無しで書いてみた。
short clip16(int x) {
 int f=(x>>31);
 x ^= f;
 x = (((-(x&-0x8000))>>31) | x) & 0x7FFF;
 x ^= f;
 return (short)x;
}

521 :デフォルトの名無しさん:2001/07/21(土) 22:50
>>518
 ええとね、PCMのクリッピングで悩む必要はないよ。
 44.1Kだから1秒に およそ9万回しかクリッピング処理は回って来ないからさ
 それより、その処理本体で悩んだ方がいいと思う

522 :デフォルトの名無しさん:2001/07/23(月) 20:17
皆さん凄いですね。
フリーソフトの作家さんが、セミコロンを使わないでCのプログラムを
書いて遊んでいたのを思い出しました。

523 :デフォルトの名無しさん:2001/07/24(火) 02:31
>>522
そんなことできるのかー。

Perlなら簡単そうだけど、Cで出来るのか。

524 :デフォルトの名無しさん:2001/07/24(火) 03:13
trigraphつかえばできそうだけどそうじゃないのかな

525 :デフォルトの名無しさん:2001/07/24(火) 03:15
ううーん
すべての
式;
はif(式){}で置き換えられるとして
変数宣言はどうするんだ

526 :デフォルトの名無しさん:2001/07/24(火) 03:18
変数は引数でもつかってりゃいいか

void sub(char *msg)
{
if(msg = "Hello world!\n", printf(msg), 0) {}
}

int main()
{
if(sub(0), 0) {}
}

527 :526:2001/07/24(火) 03:20
あmainのreturn書いてないやw
returnが書けないのか・・・
まぁ関数から値を返すときは関数に変数のポインタを渡せばいいけど
mainにreturnが書けないのはイタイ

528 :デフォルトの名無しさん:2001/07/24(火) 03:36
>>525-527
トリッキー、つーかただの嫌がらせだな(w

144 KB
■ このスレッドは過去ログ倉庫に格納されています

★スマホ版★ 掲示板に戻る 全部 前100 次100 最新50

read.cgi ver 05.04.00 2017/10/04 Walang Kapalit ★
FOX ★ DSO(Dynamic Shared Object)